2

I have a struct CRTPBase serving as a base class for curiously recurring template pattern. Its only use is to expose the derived type:

template<typename Derived>
struct CRTPBase {
    using asdf = Derived;
};

Now, I use the class as follows:

struct D : public CRTPBase<D> {
    static_assert(std::is_same<asdf, D>::value, "");
};

So far, no problem. Now, instead of using a "normal" struct, I'd like to use a templated one:

template<int N>
struct DTmpl : public CRTPBase<DTmpl<N>> {
    // the following compiles under VS2012, but not in clang
    static_assert(std::is_same<asdf, DTmpl>::value, "");
};

On VS2012, the above compiles fine, but clang needs me to mention that asdf is a type:

template<int N>
struct DTmpl : public CRTPBase<DTmpl<N>> {
    static_assert(std::is_same<typename CRTPBase<DTmpl<N>>::asdf, DTmpl>::value, "");
};

Now, I introduce another struct Intermediate, whose sole purpose is to "wrap" a given base class:

template<typename Base>
struct Intermediate : public Base {};

My intuition was that saying Intermediate<CRTPBase<..>> instead of CRTPBase<..> shall (essentially) make no difference.

However, both Visual Studio and clang compile the following:

struct DIntrmd : public Intermediate<CRTPBase<DIntrmd>> {
    static_assert(std::is_same<asdf, DIntrmd>::value, "");
};

And both Visual Studio and clang reject the following:

template<int N>
struct DTmplIntrmd : public Intermediate<CRTPBase<DTmplIntrmd<N>>> {
    static_assert(std::is_same<asdf, DTmplIntrmd>::value, "");
};

Again, I have to explicitly state that asdf is a type so that it compiles:

template<int N>
struct DTmplIntrmd : public Intermediate<CRTPBase<DTmplIntrmd<N>>> {
    static_assert(std::is_same<typename Intermediate<CRTPBase<DTmplIntrmd<N>>>::asdf, DTmplIntrmd>::value, "");
};

So, here's my question: Which is the correct compiler behaviour regarding the situation described?

phimuemue
  • 34,669
  • 9
  • 84
  • 115
  • In your first example, you could use `typename DTmpl::asdf` instead of `typename CRTPBase>::asdf`. i.e. just be lazy and use the derived class (that you are currently defining) instead of the base class. – Aaron McDaid Jul 24 '15 at 13:16

1 Answers1

3

According to [temp.res]

A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.

So in this example:

template<int N>
struct DTmpl : public CRTPBase<DTmpl<N>> {
    // the following compiles under VS2012, but not in clang
    static_assert(std::is_same<asdf, DTmpl>::value, "");
};

asdf is a name dependent on a template-parameter, so should be assumed to not name a type since it is not qualified by typename. VS2012 is wrong to compile this code, and clang is correct.

In every other example in your question, either asdf is not dependent (and both compilers accept the code) or it is dependent (and both compilers reject it). All the other behavior is correct.

For more, see Where and why do I have to put the "template" and "typename" keywords?.

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
  • For the `template` and `typename` issue I tend to answer the question directly and link to the question you linked to, as even with that link, people sometimes don't understand how to apply it to their particular problem. – TartanLlama Jul 24 '15 at 13:04