2

If T is a type, why can a normal function accept both T and const T but a specialized template function cannot? Does this mean the programmer has to type more code which defeats the purpose of using templates?

struct s
{


    void func(const char *buf)
    {
        cout << "func(const char *)" << endl;
    }


    void func(const wchar_t *buf)
    {
        cout << "func(const wchar_t *)" << endl;
    }

};

Output: Two different functions will be called for T and const T when T is char*/wchar_t*

func(const char *)
func(const wchar_t *)
func(const char *)
func(const wchar_t *)

The same but with templates:

struct ss
{
    template<typename T>
    void func (T t)
    {
        cout << "func (T)" << endl;

    }

    template<>
    void func (const char *buf)
    {
        cout << "func (const char *)" << endl;
    }

    template<>
    void func(const wchar_t *buf)
    {
        cout << "func (const wchar_t *)" << endl;
    }

};

Output: Three different functions will be called for T and const T when T is char*/wchar_t*

func (const char *)
func (const wchar_t *)
func (T)
func (T)
user3613229
  • 101
  • 4
  • 2
    With `char *`, `void func (T t)` is an exact match (with `T = char*`) whereas it has to be promote to `const char*` to be called by `void func (const char *buf)`. – Jarod42 Jun 09 '14 at 15:04
  • Yes, it would be nice if normal function are as type-safe as template functions! – user3613229 Jun 09 '14 at 15:12
  • 1
    @user3613229 What would you rather have happen? That you're forced to provide `const`/non-`const` overloads in the first case? And this doesn't have to do with type safety, but how the rules of template argument deduction are specified. Also, your code is invalid. Explicit specializations of member function templates must be made at namespace scope. – Praetorian Jun 09 '14 at 15:18
  • @user3613229 only if you want to pass half your programming time inserting typecasts... :( – Massa Jun 09 '14 at 15:21
  • @massa That's fine. I get paid by the hour. (at)Praetorian I left out the code that declares and uses the objects. – user3613229 Jun 09 '14 at 15:25
  • @user3613229 I'm gonna comment: I love C++11 because you type less and DRY more. Repeating is introducing errors. :D – Massa Jun 09 '14 at 16:23

3 Answers3

2

Quote from C++ Standard 13.3.3.2 [over.ics.rank], p.4:

Standard conversion sequences are ordered by their ranks: an Exact Match
is a better conversion than a Promotion, which is a better conversion
than a Conversion.

1

It mean that if you have struct Foo:

struct Foo {
  void boo(const char*) {
  }
};

then boo will be used with const char* because of Exact Match (no conversion needed) and char* will be used because of Conversion:

2

But if class Foo has better match method:

struct Foo {
  void boo(const char*) { // Conversion `char*` -> `const char*` needed
  }

  void boo(char*) { // Exact Match, no Conversion needed
  }
};

that method will be used:

3

For exactly the same reason template method of class Foo will be used. When boo called with parameter char * deducted type of template is char *, so it's better match then const char*:

Avoid code copy/paste

To avoid code duplication you can use explicit cast:

void boo(char* x) {
  return boo(static_cast<const char*>(x));
}

or SFINAE:

template <class T>
void boo(T*) {
  using WithoutCV = typename std::remove_cv<T>::type;
  static_assert(std::is_same<WithoutCV, char>::value, "");
}

Note

Note that if T is not a pointer then you can't declare overloaded functions with T and const T arguments because they are the same:

  • Yes I know there are workarounds but it would be nice if the language was more consistent about these things. These are the reasons why I would like to move away from c++ and find a new language. – user3613229 Jun 10 '14 at 08:58
1

To quote Jarod42's comment:

With char *, void func (T t) is an exact match (with T = char*) whereas it has to be promote to const char* to be called by void func (const char *buf).

The compiler prefers to use an exact match wherever possible.

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
-1

C++ is type-safe programming language. Some type and its const version are 2 different types. For this reason you got such output. When you specialize your template function you specialize it only for one given type. And when you have normal function some casting is allowed such as char* -> const char* but const char* -> char* is forbidden because you mustn't change value of const char* in your function.

Dakorn
  • 883
  • 6
  • 11
  • -1: He wants it to go `char*` -> `const char*` in the template case, too, so he's not expecting it to remove constness. – Ken Bloom Jun 09 '14 at 15:38
  • I know what he tried to do. But I tried explain also why he cant do it using ordinary specialization. Maybe I fail, than I can only say sorry. If he wants to use some tricks maybe this subject will help: [link](http://stackoverflow.com/questions/14926482/const-and-non-const-template-specialization) – Dakorn Jun 09 '14 at 18:02