开发者

Compiler chooses wrong template function specialization

I'm desperately trying to get my specializations working but still having non-compilable code due to deducing arguments to incorrect one. Note, that the errors are not about defining the templates but about applying irrelevant operation in wrong template implementation. The reduced example of code demonstrating the problem, is that:

struct Test { void Method() const {} };

template<typename T>
void Cmp(T _val) { _val > 1; }

template<>
void Cmp&l开发者_StackOverflowt;const Test &>(const Test &_val) { _val.Method(); }

template<>
void Cmp<const char *>(const char *_val) { _val[2]; }

int main()
{
  Test test1;
  char test2[5];

  Cmp(10);    // ok, expected
  Cmp(test1); // error in Cmp(T)?! but expecting to instantiate Cmp(const Test &)
  Cmp(test2); // error in Cmp(T)?! but expecting to instantiate Cmp(const char *)
  return 0;
}

I really don't wish to use explicit calls like Cmp<const Test &>(test1) (that works) as AFAIK the compiler should be able to deduce the arguments automagically and the whole idea behind these specializations is dispatching Cmp calls transparently (in real code, I'm defining operators). Of course, by-value specialization Cmp<Test>(Test) works as expected but for large sophisticated non-POD class it's just ridiculous to pass it by value.

Whatever fixes I try to apply the compiler just stubbornly refuses to pick the by-reference specialization using the general template instead. It seems I'm missing something important but I'm really run out of ideas why my approach doesn't work and how I should construct code expressing such a simple concept from non-templated C++ world as passing classes by reference. Of course, Google proven to be utterly useless for this problem. ^_^ I tried GCC 4.2.1 and 4.4.6.


Cmp(test1);

Here, T is deduced from the argument to be Test. It is not deduced to be const Test& so your specialization is not a match, hence why the primary template is instantiated. You would need to make your specialization take a Test by value. With this declaration, the specialization is indeed used:

template<>
void Cmp<Test>(Test _val) { _val.Method(); }

Cmp(test1);

Here, T is deduced to be char*, not const char*, so the specialization doesn't match. You would need to specialize for char* instead of const char* to match this. Alternatively, you can convert the argument to const char* when making the call:

const char* test2ptr = test2;
Cmp(test2ptr); 

All that said, why specialize at all when you can overload?

template<typename T>
void Cmp(T _val) { _val > 1; }

void Cmp(const Test &_val) { _val.Method(); }

void Cmp(const char *_val) { _val[2]; }

// Add an overload to support arrays of char:
template <unsigned N>
void Cmp(const char (&_val)[N]) { _val[1]; }

You really should avoid specializing function templates. It's difficult and in most cases is just not worth the trouble.


Ehm... why specialize? Just overload it..

void Cmp(const Test &_val) { _val.Method(); }

void Cmp(const char *_val) { _val[2]; }

100% guarantee to pick these methods.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜