template<typename T> struct A {
auto func() -> decltype(T::func()) {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
对我来说似乎很简单。但是MSVC无法编译。
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
即使编译器很乐意接受调用该函数。下面的样本编译得很好。
template<typename T> struct A {
void func() {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
我在尝试使用模板参数中的任何类型时遇到了同样的问题。
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'
而B类明确定义了一种叫做“某事”的类型。编译器非常乐意在T,T&amp;类型的对象上调用函数。或T *,但我似乎无法访问T中的任何类型。
答案 0 :(得分:3)
您在宣布之前尝试使用T::func
。这就是编译器对你大喊大叫的原因。请注意,当您从类派生时,如果类来自类模板,则会生成该类。并且隐式生成类(称为隐式实例化)需要为其所有成员生成声明(因此编译器知道类的sizeof值,并且可以对其执行查找)。
因此它也会实例化声明auto func() -> decltype(T::func())
,并且肯定会失败。
答案 1 :(得分:2)
您的代码似乎存在一些问题,其中一个问题看起来像VS10错误。
T::func()
致电A
而未将A
强制转换为T
,这是CRTP的一部分,因为A
不是来自T
return static_cast<T*>(this)->func();
。 - FixL decltype
func
的内容看起来像是一个静态函数调用,而decltype
实际上是一个实例函数。由于decltype(static_cast<T*>(nullptr)->func())
不实际运行该功能,您应该执行以下操作func
B
在A
中是私有的,无法从A
调用 - 修正:将struct
更改为B
decltype
中使用未定义的类func
。作为一种解决方法,您可以将decltype
重构为基类吗? (现在我们需要两个模板参数,一个用于转换,一个用于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 {
};
,因此创建一个新的习语CRTPEX)
decltype
我看到g ++也对此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() {}
};
感到窒息,任何人都可以确认这是一个缺陷吗?如果是这样,我将为微软打开一个错误。我的理解是下面的代码是有效的,但是g ++和VC10都没有编译它。
{{1}}
答案 2 :(得分:1)
首先,我认为接近正确的代码是:
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(){
}
};
正如Motti指出的那样。但是仍然失败了,我想因为当B
被解除为从A<B>
继承时必须知道基数的返回类型,但是因为{{ 1}}尚未定义,它成为鸡和蛋的问题。
但是,B
可能最终只能使用C++1y
(不使用auto
),我尝试使用decltype
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(){
}
};
)并运行:
c++ -std=c++1y
两个免责声明:我不知道为什么会这样。我不知道它有多标准。