在派生模板中使用 typedef 时,C++ 虚拟模板参数引发错误 class

C++ Dummy template parameter inducing error while using a typedef in derived template class

我正在尝试修复我在使用此代码时遇到的一个奇怪错误。这是一个可以复制错误的最小示例:

test11.cpp:

namespace detail{
   template <auto UInt>
   class Test{
      public:
         typedef decltype(UInt) value_type;

         Test (const value_type& x = 0);

      protected:
         value_type n;
   };

   template<auto UInt>
   Test<UInt>::Test (const value_type& x) : n(x){}

   // Here, void would be substitute with some enable_if stuff
   template <auto UInt, typename = void>
   class TestChild : public Test<UInt>{
      public:
         typedef typename Test<UInt>::value_type value_type;

         TestChild (const value_type& x = 0);
         value_type foo() const;
   };

   template<auto UInt>
   TestChild<UInt>::TestChild (const value_type& x) : Test<UInt>(x){}

   template<auto UInt>
   value_type TestChild<UInt>::foo(){
      value_type ret=42;
      return ret;
   }
}

int main(){}

我在 Ubuntu 16.04 LTS 中使用 GCC 7.2.0 和 Clang 5.0.0 编译了它。您可以看到这两个演示链接:

gcc 中的错误信息是这样的:

test11.cpp:27:38: error: ‘value_type’ does not name a type
    TestChild<UInt>::TestChild (const value_type& x) : Test<UInt>(x){}
                                      ^~~~~~~~~~
test11.cpp:27:51: error: invalid use of incomplete type ‘class detail::TestChild<UInt>’
    TestChild<UInt>::TestChild (const value_type& x) : Test<UInt>(x){}
                                                   ^
test11.cpp:18:10: note: declaration of ‘class detail::TestChild<UInt>’
    class TestChild : public Test<UInt>{
          ^~~~~~~~~
test11.cpp:30:4: error: ‘value_type’ does not name a type
    value_type TestChild<UInt>::foo(){
    ^~~~~~~~~~

此外,对我来说真正奇怪的是,如果我在 class TestChild 的模板中省略虚拟参数(我的意思是 template<auto UInt> 而不是template<auto UInt, typename = void>),我仍然收到如下所示的(较短的)错误:

test11.cpp:30:4: error: ‘value_type’ does not name a type
    value_type TestChild<UInt>::foo(){
    ^~~~~~~~~~

您可以查看 GCC 7.2.0 的演示 here

看起来主要的错误是,如果我在 class 之外定义函数,typedef typename Test<UInt>::value_type value_type; 并没有被真正检测到(我不知道我是否解释清楚了) .

如果我在 class 中定义函数时也会发生这种情况,这对我来说是有意义的,但事实并非如此,因为在最后一种情况下一切都可以正常编译(您可以在 demo 如果你愿意的话)。

总之,我的主要问题是我想编译这个程序,但要记住我必须将声明与定义分开。所以我展示的最后一个演示(所有内容都在 class 内定义)是我想要实现的,但是模块化。

我希望有人能帮助我并解释这段代码是怎么回事。

您应该(至少)进行三处更改。

首先:为 TestChild 添加第二个(默认)模板值。

所以

//................vvvvvvvvvvvv
template<auto UInt, typename V>
TestChild<UInt, V>::TestChild (const value_type& x) : Test<UInt>(x){}
//............^^^

foo() 方法也是如此

其次:记住foo()const

所以

template <auto UInt, typename V>
value_type TestChild<UInt, V>::foo() const {
   value_type ret=42;  // ...........^^^^^
   return ret;
}

第三:对于return类型对于foo()显式class

所以 typename TestChild<UInt, V>::value_type 而不是 value_type

template <auto UInt, typename V>
typename TestChild<UInt, V>::value_type TestChild<UInt, V>::foo() const {
   value_type ret=42;
   return ret;
}

或者,如果您愿意,可以使用 auto ... -> return 类型语法

template<auto UInt, typename V>
auto TestChild<UInt, V>::foo() const -> value_type {
   value_type ret=42;
   return ret;
}

或简单地auto(但也在方法声明中)

auto foo() const;

// ...

template<auto UInt, typename V>
auto TestChild<UInt, V>::foo() const {
   value_type ret=42;
   return ret;
}