dimanche 28 juin 2015

How to distingush between template class and implicit template argument inside class defintion? [duplicate]

This question already has an answer here:

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.)


Thanks to @dyp and @T.C. I could write two three solutions:

0) cast the magic spell B::template B

template<class T>
struct B{
    friend void g(B b){
        fun<A, void>(); // here A is a template class, ok
        fun<B::template B, void>(); // no error now
    } //A here is implicitly A<T>, 
};

1) specify namespace somehow (needs to know the enclosing namespace)

template<class T>
struct B{
    friend void g(B b){
        fun<A, void>(); // here A is a template class, ok
        fun<::B, void>(); // no error now
    } //A here is implicitly A<T>, 
};

2) Define alias template

template<class T>
struct B{
    template<class TT> using BB = B<TT>; // couldn't put inside the g function
    friend void g(B b){
        fun<A, void>(); // here A is a template class, ok
        fun<BB, void>(); // no error
    } //A here is implicitly A<T>, 
};

(none of the two is ideal, but it is a good workaround) The first is an ideal workaround.

Aucun commentaire:

Enregistrer un commentaire