0

I have a string class:

#include <stdint.h>

class CString {
public:
    CString() {}
    explicit CString(uint64_t ui64, int width = -1, int base = 10, char fillChar = ' ') {}
    CString(const char * str) {}

    CString arg(const CString& argument) const {return CString();}

    template <typename T>
    inline CString arg(T argument, int width = -1, int base = 10, char fillChar = ' ') const
    {
        return arg(CString(argument, width, base, fillChar));
    }
};

Now, I'm using this class:

void main()
{
    CString str;
    str.arg("123");
}

And get the error:

error C2665: 'CString::CString' : none of the 4 overloads could convert all the argument types
1>          source.cpp(6): could be 'CString::CString(uint64_t,int,int,char)'
1>          while trying to match the argument list '(const char *, int, int, char)'
1>          source.cpp(22) : see reference to function template instantiation 'CString CString::arg<const char*>(T,int,int,char) const' being compiled
1>          with
1>          [
1>              T=const char *
1>          ]

Why doesn't arg(CString&) get called, using the CString(const char *) constructor?

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335

2 Answers2

3

Note: This answers the original question, before it was changed into a different one.

why doesn't template arg overload work?

Because it requires at least two arguments, and you are passing one.

template <typename T>
inline CString arg(T argument, int width, int base = 10, char fillChar = ' ')
{ ... }
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
1

When you call

str.arg("123");

the best match is obtained via the function template arg, since CString arg(const CString& argument) requires a conversion to a user defined type. The function template then calls

return arg(CString(argument, width, base, fillChar));

but there is no CString constructor that matches the argument list const char*, int, int, char that you are passing here.

There can be no call to CString(uint64_t, int, int, char) because the conversion from const char* to uint64_t is an invalid conversion. This simplified code sample exhibits the same problem:

#include <cstdint>
void foo(std::uint64_t) {}

int main()
{
  foo("hello");
}

error: invalid conversion from 'const char*' to 'uint64_t {aka long long unsigned int}' [-fpermissive]

foo("hello");

If you were to comment out the member function template arg, then CString arg(const CString& argument) would be called, via the implicit conversion from const char* to CString.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • I understand that. My question is: "Why doesn't `arg(CString&)` get called, using the `CString(const char *)` constructor?" – Violet Giraffe Dec 25 '13 at 10:41
  • @VioletGiraffe because the template `arg` can provide a better match, whereas `CString arg(const CString&)` requires a user defined conversion. If you comment out the template `arg`, the code would compile fine. I may put this into the answer. – juanchopanza Dec 25 '13 at 10:45
  • Is overload matching always performed 1 step at a time? If the compiler could see 2 steps ahead, it would be clear that template `arg` function is a poor match. – Violet Giraffe Dec 25 '13 at 10:50
  • @VioletGiraffe the answer would be "those are the overload rules as set out in the C++ standard". I could fish out all the relevant quotes, but that would just be saying the same thing in different words. – juanchopanza Dec 25 '13 at 10:51