template<typename T> struct A {
auto func() -> decltype(T::func()) {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
Seems pretty simple to me. But MSVC fails to compile.
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'func' : is not a member of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see declaration of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see reference to class template instantiation 'A<T>' being compiled
with
[
T=B
]
visual studio 2010\projects\temp\temp\main.cpp(4): error C3861: 'func': identifier not found
Even though the compiler will happily accept calling the function. The below sample compiles fine.
template<typename T> struct A {
void func() {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
I've got the same issue trying to use any types from the template argument.
template<typename T> struct A {
typedef typename T::something something;
};
class B : public A<B> {
typedef char something;
};
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'something' : is not a member of 'B'
Whereas class B clearly defines a type called "something". The compiler is perfectly happy to call functions on an object of type T, T& or T*, but I can't seem to access any types from T.
You are trying to use T::func
before it was declared. That's why the compiler shouts at you. Notice that when you derive from a class, the class is generated if it comes from a class template. And the implicit generation of the class (which is called implicit instantiation) necessiates the generation of declarations for all its members (so the compiler knows the sizeof value of the class, and can perform lookup into it).
So it also instantiates the declaration auto func() -> decltype(T::func())
and surely fails here.
There seem to be several issues with your code, one of which looks like a VS10 bug.
T::func()
from A
without casting A
to T
, this is needed as part of CRTP since A
doesn't derive from T
. -- FixL return static_cast<T*>(this)->func();
decltype
looks like a static function invocation while func
is in fact an instance function. Since decltype
doesn't actually run the function you should do something like this decltype(static_cast<T*>(nullptr)->func())
func
is private in B
and can't be called from A
-- Fix: change A
to be a struct
B
in the decltype
.As a workaround can you refactor func
out into a base class? (now we need two template parameters, one for casting to and one for decltype
thus creating a new idiom CRTPEX)
struct Base {
void func() { }
};
template<typename T, typename U> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<U*>(this)->func();
}
};
struct B : public A<Base, B>, public Base {
};
I see that g++ also chokes on this decltype
can anyone confirm that this is a defect? If so I will open a bug for Microsoft. It is my understanding that the following code is valid but neither g++ nor VC10 compile it.
template<typename T> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<T*>(this)->func();
}
};
struct B : public A<B> {
void func() {}
};
First, I think that the close-to-proper code is:
template<typename T> struct A {
auto func()
-> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
As Motti pointed out. However that still fails, and I think for the reason that the return type of the base has to be known when B
is declated to inherit from A<B>
, but since B
is not defined yet, it becomes a chicken and egg problem.
However, it may be finally be possible in C++1y
by using simply auto
(without decltype
), I tried with gcc-4.8.2
template<typename T> struct A {
auto func()
//c++1y// -> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
This compiles (c++ -std=c++1y
) and runs:
int main(){
B b; b.func();
}
Two disclaimers: I don't know why this works. I don't know how standard it is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With