【问题标题】:How to derive from a nested class of a variadic template argument?如何从可变参数模板参数的嵌套类派生?
【发布时间】:2013-11-10 03:54:34
【问题描述】:

鉴于以下两个结构,一个可以从嵌套的“嵌套”类派生,并从派生对象调用 foo() 和 bar():

struct WithNested1 {
    template<class T> struct Nested {
        void foo();
    };
};

struct WithNested2 {
    template<class T> struct Nested {
        void bar();
    };
};

struct Test : WithNested1::Nested<Test>,
              WithNested2::Nested<Test>
{

};

Test test;
test.foo();
test.bar();


但是,如果两个外部类都作为可变参数模板参数传递,您将如何从它们派生?

例如编译失败:

template<typename... Ts>
struct Test : Ts::template Nested<Test>...
{

};

Test<WithNested1, WithNested2> test;
test.foo();
test.bar();

错误:“foo”:不是“测试”的成员
错误:'bar':不是'Test'的成员

奇怪的是,如果对 foo() 和 bar() 的调用被删除,它就会编译。

【问题讨论】:

    标签: c++ templates c++11 variadic-templates crtp


    【解决方案1】:
    template <typename... Ts>                                                          
    struct Test : Ts::template Nested<Test<Ts...>>...                                  
    {                                                                                  
    
    };  
    

    这与上面的答案相同,但我想我会解释它是如何工作的。首先在你的例子中Test 没有模板参数(编译器应该警告你),但我们应该给它。 CRTP 的重点是为您提供从与您的类型相同的模板参数继承的类,这样它就可以通过模板参数访问您的方法和成员。在这种情况下,您的类型是 Test&lt;Ts...&gt;,因此您必须通过它。正如@aschepler 通常已经指出的那样,您可以单独使用Test,但在您已经在课堂上之前它不在范围内。

    我认为这是一种更简洁的方式来做你想做的事。

    template <typename T>                                                              
    struct A {                                                                         
        void bar (){                                                                   
            static_cast<T*>(this)->val = 3;                                            
        }                                                                              
    };                                                                                 
    
    template <typename T>                                                              
    struct B {                                                                         
        void foo (){                                                                   
            static_cast<T*>(this)->val = 90;                                           
        }                                                                              
    };                                                                                 
    
    
    template <template<class> class ... Ts>                                            
    struct Test : Ts<Test<Ts...>>...                                                   
    {                                                                                  
        int val;                                                                       
    };                                                                                 
    
    int main() {                                                                       
        Test<A,B> test;                                                                
        test.foo();                                                                    
        test.bar();                                                                    
        return 0;                                                                      
    }  
    

    【讨论】:

    • 嘿,谢谢!你帖子的后半部分实际上是唯一对我有用的东西。我尝试在 Visual Studio 和 mingw 中使用 Test ,但没人会接受。另外,我不知道你可以传递一个没有 s. 的模板
    • @bitwise visual studio 有时在 c++11 功能上落后,至于没有 读取模板模板参数的模板
    • 我认为这有点轻描淡写 =)
    【解决方案2】:

    “注入的类名”Test 可用作Test&lt;Ts...&gt; 的缩写,不在您尝试使用Nested&lt;Test&gt; 的范围内,因为类范围直到{ 标记才开始。

    使用

    template<typename... Ts>
    struct Test : public Ts::template Nested<Test<Ts...>>...
    {
    };
    

    【讨论】:

    • 我最喜欢这个解释,因为如果没有参数,Test 将无法工作,尽管一个好的编译器只会告诉你它需要模板参数
    【解决方案3】:

    这个works

    template<typename... Ts>
    struct Test : Ts::template Nested<Test<Ts...>>...
    //                                    ^^^^^^^
    {
    };
    

    9/2:

    [...]。类名也插入到类本身的范围;这被称为注入类名。出于访问检查的目的,注入的类名被视为公共成员名。 [...]

    14.6.1/1:

    与普通(非模板)类一样,类模板具有注入类名称(第 9 条)。注入的类名可以用作模板名或类型名。当它与模板参数列表一起使用时,作为模板模板参数的模板参数,或作为朋友类模板声明的详细类型说明符中的最终标识符,它指的是类模板本身。否则,它相当于模板名称后跟 .

    中包含的类模板的模板参数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-08
      • 1970-01-01
      • 2011-04-15
      相关资源
      最近更新 更多