CRTP error with XCode 4.5.2 - Parse Issue, expected expression

306 Views Asked by At

I am using CRTP to implement something but am stuck on an error in XCode 4.5.2. The following code is a simplified version that still replicates the error. It occurs on the line where the method Api::Enable is defined and has something to do with the fact that there are no parameters when Api::Enable calls this->T::Enable

enum Enum
{
    FOO,
    BAR,
    BAZ,
};

template <typename T>
class Api
{
public:
    template <Enum E, bool On> void Enable() {static_cast<T *>(this)->Enable<E, On>();}
};

class ApiImpl : public Api<ApiImpl>
{
public:
    template <Enum E, bool On> void Enable() {}
};

int main(int argc, const char * argv[])
{
    ApiImpl clsApi;
    clsApi.Enable<FOO, true>();
    return 0;
}

Here is a screenshot of the error in Xcode: https://i.stack.imgur.com/YUHtt.png. I get the same error whether I use "Apple LLVM compiler 4.1" or "LLVM GCC 4.2". MSVC Express 2010 compiles without error.

Note that adding a function parameter causes the error to disappear. The following compiles fine:

enum Enum
{
    FOO,
    BAR,
    BAZ,
};

template <typename T>
class Api
{
public:
    template <Enum E , bool On> void Enable(unsigned int X) {static_cast<T *>(this)->Enable<E, On>(X);}
};

class ApiImpl : public Api<ApiImpl>
{
public:
    template <Enum E, bool On> void Enable(unsigned int) {}
};

int main(int argc, const char * argv[])
{
    ApiImpl clsApi;
    clsApi.Enable<FOO, true>(0);
    return 0;
}
1

There are 1 best solutions below

0
Anton Savin On BEST ANSWER

You should use template keyword to resolve dependent template names:

template <Enum E, bool On> void Enable() {
    static_cast<T*>(this)->template Enable<E, On>();
}

C++11, [temp.names]/4:

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

If Enable() is for example template <typename T> void Enable(){}, then clang shows an error: error: use 'template' keyword to treat 'Enable' as a dependent template name.

I don't know why it produces that irrelevant message in your case (when template arguments are not types). I think this can be posted as bug report. (I tested on clang 3.6 - the same).

Also, gcc 4.8 and 4.9 don't produce any errors on this code which I beleive is also incorrect.