2

C++ allows template arguments that refer to template classes, not instances of it. For example the function fun below.

At the same time there is a feature by which template arguments can be omitted inside a class definition. For example in the definition of template<class T> class A, we can say A to imply A<T>.

I found a case where both rules potentially can produce an ambiguity. Moreover I cannot solve the ambiguity. Here it is a MWE, in which in the definition of template<class T> class B I need to refer to B as a template class and not as B<T>.

template <template<class> class Y, class T>
auto fun(){return Y<T>{};} // fun can be used with a *template* class

template<class T>
struct A{
    friend void f(A a){} //A here is implicitly A<T>, ok 
};

template<class T>
struct B{
    friend void g(B b){
        fun<A, void>(); // here A is a template class, ok
        fun<B, void>(); // error: no matching function for call to 'fun' because the compiler sees B<T>, not B
    } //A here is implicitly A<T>, 
};

int main(){
    A<void> a{};
    B<void> b{};
    g(b);
}

(I need to do this because the function g is a friend function that I want to define inside the class.)

Clang 3.5 gives the error described above, and GCC 4.9.2 is ok with it. The worst part is that I cannot make additional specifications and resolve the ambiguity.

For example I tried:

    fun<struct B, void>();

    fun<template<class> struct B, void>();

but still get the same error.

Is there a way to tell clang (or a problematic compiler) that B is not B<T> but the template class B?

(I used some C++11 syntax to simplify the example, but the problem iapplies to C++98 as well. Please correct or let me know if I am not using the right naming conventions.)

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
alfC
  • 14,261
  • 4
  • 67
  • 118
  • 1
    It should be an even bigger issue with `template – dyp Jun 27 '15 at 09:43
  • Btw, each instantiation of the class template `B` contains an *injected-class-name* that refers to the current instantiation. Inside `B`, the name `B` can therefore refer to both, the injected-class-name (i.e. class) and the class template `B` itself. – dyp Jun 27 '15 at 09:46
  • The namespace trick worked (code is `fun();`). If I understand correctly, the other seems to work too, (code: `fun();`) but requires this line `template using BB = B;` and if outside the class additionally a predeclaration of `template class B;`. The namespace seems more noisy. Code works with gcc and clang. – alfC Jun 27 '15 at 10:50
  • 2
    This is a [known clang bug](https://llvm.org/bugs/show_bug.cgi?id=9551). I kinda like the `B::template B` workaround suggested in the accepted answer of the linked dup. – T.C. Jun 27 '15 at 11:09

0 Answers0