5
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 访问任何类型。

4

3 回答 3

3

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

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

于 2010-11-21T11:59:15.780 回答
2

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

  1. 您在没有强制转换的情况下调用T::func()from ,这是 CRTP 的一部分,因为它不是派生自. -- 修复AATATreturn static_cast<T*>(this)->func();
  2. 您传递给的东西decltype看起来像一个静态函数调用,而func实际上是一个实例函数。由于decltype 实际上并未运行该功能,因此您应该执行以下操作decltype(static_cast<T*>(nullptr)->func())
  3. func是私有的B,不能被调用A——修复:更改Astruct
  4. 这看起来像 VS10 中的一个错误,即使在所有这些修复之后,我仍然收到一个错误,您试图Bdecltype.

作为一种解决方法,您可以重构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() {}
};
于 2010-11-21T09:22:40.940 回答
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(){
    }
};

正如莫蒂指出的那样。然而,这仍然失败,我认为由于必须知道基的返回类型何时B被声明为继承自A<B>,但由于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();
}

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

于 2013-11-02T05:37:00.457 回答