简体   繁体   中英

Can't get this pesky CRTPish syntax right

Consider the following code:

class A {
    virtual void foo() = 0;
};

template <template <typename... Ts> class SubA, typename... Ts>
class Helper : public A {
    static void bar();
    virtual void foo() override final {
        return bar();
    }
};

template <typename T>
class NiceA : Helper<NiceA, T> {    };

This compiles. Edit: If I now add:

template <>
void Helper<NiceA, int>::bar()
{
    std::cout << "Hi." << std:: endl;
}

this explicit instantiation compiles. But if I add instead:

template <typename T>
void Helper<NiceA, T>::bar()
{
    std::cout << "Hi." << std:: endl;
}

this fails with the error:

a.cpp:22:28: error: invalid use of incomplete type ‘class Helper<NiceA, T>’
 void Helper<NiceA, T>::bar()
                            ^
a.cpp:10:7: error: declaration of ‘class Helper<NiceA, T>’
 class Helper : public A {
       ^

Why?

Note: Compiling with gcc 4.9.3.

First of all, note that this has nothing to do with CRTP, ie it has nothing to do with NiceA inheriting from Helper . Also, it has nothing to do with Helper inheriting from A or that virtual function.

Thus, here is the actual code for the question:

template <template <typename... Ts> class SubA, typename... Ts>
class Helper
{
  static void bar();
};

template <typename T>
class NiceA
{
};

template <>  // This compiles fine
void Helper<NiceA, int>::bar()
{
}

template <typename T>  // This does not
void Helper<NiceA, T>::bar()
{
}

int main()
{
}

Just saying, because by giving an MCVE you make the job easier for those who would like to give an answer.

Now, why does it not compile? You cannot partially specialize a single member function. Period.

You need to partially specialize the whole class.

// Partially specialize Helper
template <typename T>
class Helper<NiceA, T>
{
  static void bar();
};

// Now implement the member function
template <typename T>
void Helper<NiceA, T>::bar()
{
}

You're simply mis-defining your member function:

template <typename T>
void Helper<NiceA, int>::bar()
{
    std::cout << "Hi." << std:: endl;
}

That would be the definition for a function template bar<T>() in Helper<NiceA, int> . But bar() is just a normal function, so you don't need to specify any template parameters:

template <> // <== nothing
void Helper<NiceA, int>::bar()
{
    std::cout << "Hi." << std:: endl;
}

Clang's error is much more helpful in this particular instance:

main.cpp:19:1: error: template parameter list matching the non-templated nested type 'Helper<NiceA, int>' should be empty ('template<>')
template <typename T>
^        ~~~~~~~~~~~~

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM