CRTP失败w / decltype

时间:2010-11-19 14:03:02

标签: c++ visual-c++ c++11 crtp decltype

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中的任何类型。

3 个答案:

答案 0 :(得分:3)

您在宣布之前尝试使用T::func。这就是编译器对你大喊大叫的原因。请注意,当您从类派生时,如果类来自类模板,则会生成该类。并且隐式生成类(称为隐式实例化)需要为其所有成员生成声明(因此编译器知道类的sizeof值,并且可以对其执行查找)。

因此它也会实例化声明auto func() -> decltype(T::func()),并且肯定会失败。

答案 1 :(得分:2)

您的代码似乎存在一些问题,其中一个问题看起来像VS10错误。

  1. 您从T::func()致电A而未将A强制转换为T,这是CRTP的一部分,因为A不是来自T return static_cast<T*>(this)->func();。 - FixL decltype
  2. 您传递给func的内容看起来像是一个静态函数调用,而decltype实际上是一个实例函数。由于decltype(static_cast<T*>(nullptr)->func()) 实际运行该功能,您应该执行以下操作func
  3. BA中是私有的,无法从A调用 - 修正:将struct更改为B
  4. 这看起来像是VS10中的一个错误,即使在所有这些修复之后,我也会收到错误,您试图在decltype中使用未定义的类func
  5. 作为一种解决方法,您可以将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

两个免责声明:我不知道为什么会这样。我不知道它有多标准。