【问题标题】:CRTP fails w/ decltypeCRTP 失败 w/decltype
【发布时间】:2010-11-19 14:03:01
【问题描述】:
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& 或 T* 类型的对象上调用函数,但我似乎无法从 T 访问任何类型。

【问题讨论】:

  • 编译器不会愉快地实例化 A::func,我们在您的 previous question 中介绍了这一点。
  • 你可以认为这是一个竞态条件:A 的实例化取决于 B 的定义,因为 A::func 的返回类型取决于 B::func 的返回类型,然而定义 B(并因此声明 B::func)依赖于 A 作为基类。
  • @Fred:关于我的 CRTP 失败,你说得对。但是,如果您想让答案被接受,您必须将其作为一个发布,而不是评论。
  • 我认为这不值得回答,需要用 0x 仔细检查。

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


【解决方案1】:

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

所以它也实例化了声明 auto func() -&gt; decltype(T::func()) 并且在这里肯定会失败。

【讨论】:

    【解决方案2】:

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

    1. 您从A 调用T::func() 而不将A 转换为T,这是CRTP 的一部分,因为A 不是从T 派生的。 -- 修复return static_cast&lt;T*&gt;(this)-&gt;func();
    2. 您传递给decltype 的内容看起来像一个静态函数调用,而func 实际上是一个实例函数。由于decltype 实际运行该功能,你应该做这样的事情decltype(static_cast&lt;T*&gt;(nullptr)-&gt;func())
    3. funcB 中是私有的,不能从 A 调用 -- 修复:将 A 更改为 struct
    4. 这看起来像是 VS10 中的一个错误,即使在所有这些修复之后,我仍然收到一个错误,即您尝试在 decltype 中使用未定义的类 B

    作为一种解决方法,您可以将func 重构为基类吗? (现在我们需要两个模板参数,一个用于强制转换,一个用于decltype,从而创建一个新的成语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 {
    };
    

    我看到 g++ 也对这个 decltype 感到窒息,任何人都可以确认这是一个缺陷吗?如果是这样,我将为 Microsoft 打开一个错误。我的理解是下面的代码是有效的,但是 g++ 和 VC10 都没有编译它。

    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() {}
    };
    

    【讨论】:

    • 如果您在 Visual C++ 中发现了错误,请考虑在connect.microsoft.com 提交错误报告(如果您确实提交了错误,请在此处发布链接,以便人们知道它已被报告)。跨度>
    • @James,我正在提交一个错误,但发现 g++ 中的行为是相同的(请参阅我对问题的编辑)。
    • 不,你不能。如果您尝试这样做,则会收到内部 MSBuild 错误。
    • @DeadMG,“不,你不能”什么?你能说得更具体点吗?
    • @Motti:对不起-错误。你不能做 Base 的事情,因为你不能将 A 转换为 Base。
    【解决方案3】:

    首先,我认为接近正确的代码是:

    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(){
        }
    };
    

    正如莫蒂指出的那样。但是 still 失败了,我认为当B 被声明为继承自A&lt;B&gt; 时,必须知道基的返回类型,但因为没有定义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) 并运行:

    int main(){
      B b; b.func();
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-21
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-12
      相关资源
      最近更新 更多