3

给定以下两个结构,一个可以从两个嵌套的“嵌套”类派生,并从派生对象调用 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':不是'Test'的成员
错误:'bar':不是'Test'的成员

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

4

3 回答 3

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

};  

这与上面的答案相同,但我想我会解释它是如何工作的。首先在您的示例Test中没有模板参数(编译器应该警告您),但我们应该给它。CRTP 的重点是为您提供从与您的类型相同的模板参数继承的类,这样它就可以通过模板参数访问您的方法和成员。在这种情况下,您的类型Test<Ts...>就是您必须通过的类型。正如@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;                                                                      
}  
于 2013-11-10T04:09:59.943 回答
2

Test可以用作缩写的“注入的类名”Test<Ts...>不在您尝试使用Nested<Test>的范围内,因为类范围直到{令牌才开始。

利用

template<typename... Ts>
struct Test : public Ts::template Nested<Test<Ts...>>...
{
};
于 2013-11-10T04:10:07.697 回答
2

有效

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

9/2:

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

14.6.1/1:

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

于 2013-11-10T04:05:10.267 回答