我目前正在使用C ++中的template
,并且遇到了template template parameters
。
假设我有以下课程:
template<typename T>
struct MyInterface
{
virtual T Foo() = 0;
}
class MyImpl : public MyInterface<int>
{
public:
int Foo() { /*...*/ }
};
template< template<typename T> typename ImplType>
class MyHub
{
public:
static T Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
从本质上讲,我希望static class
类似MyHub
接受MyInterface
的实施,并提供某些static
方法来使用它们static T Foo()
点。
然后我尝试使用MyHub
:
int main()
{
int i = MyHub<MyImpl>::Foo();
return 0;
}
不幸的是,我总是收到一条错误消息,指出T
(MyHub中的static T Foo()
)类型没有命名类型。
我希望它有效,因为
Impl
的模板参数名为T MyHub
是带有一个模板参数的模板化类,包含方法Foo
到目前为止,我在挖掘文档和谷歌搜索结果后找不到解决方案,所以我希望你们中的一些人可以帮助我。
答案 0 :(得分:5)
您可以使用typedef。此外,由于您的实现类不是模板类,因此不需要模板模板参数。
#include <iostream>
#include <string>
template<typename T>
struct MyInterface
{
virtual T Foo() = 0;
typedef T Type;
};
class MyIntImpl : public MyInterface<int>
{
public:
int Foo() { return 2; }
};
class MyStringImpl : public MyInterface<std::string>
{
public:
std::string Foo() { return "haha"; }
};
template<class ImplType>
class MyHub
{
public:
static typename ImplType::Type Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
int main()
{
std::cout << MyHub<MyIntImpl>::Foo() << "\n"; // prints 2
std::cout << MyHub<MyStringImpl>::Foo() << "\n"; // print haha
return 0;
}
Here就是一个例子。
答案 1 :(得分:3)
STL使用value_type作为模板类的基础类型的占位符。你可以为你的解决方案做同样的事情。
template<typename T>
struct MyInterface
{
typedef T value_type;
virtual T Foo() = 0;
}
class MyImpl : public MyInterface<int>
{
public:
int Foo() { /*...*/ }
};
template<typename ImplType>
class MyHub
{
public:
static typename ImplType::value_type Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
另请注意,在c ++ 14中,typename ImplType::value_type
可以替换为auto
:
static auto Foo()
{
ImplType i;
return i.Foo();
}
答案 2 :(得分:3)
MyImpl
不是类模板;因此无法作为MyInterface
的模板参数传递。
您可以将MyInterface
,MyImpl
和MyHub
课程更改为:
template<typename T>
class MyInterface{
public:
virtual T foo() = 0;
};
class MyImpl: public MyInterface<int>{
public:
using value_type = int;
value_type foo(){ return 1; /* dummy */ }
};
template<typename Impl, typename = std::enable_if_t<std::is_base_of<Impl, MyInterface<typename Impl::value_type>>::value>>
class MyHub{
public:
static auto foo(){
static Impl i;
return i.foo();
}
};
让您以与示例相同的方式使用它。
在这种情况下,std::is_base_of
检查可能有点不必要;但是,通过这种方式,您无法通过方法MyInterface
意外传入另一个不是foo()
的类。
答案 3 :(得分:2)
模板模板参数的模板参数名称实际上是纯粹的文档化构造 - 它们不会包含在包含模板的范围内。
这是有充分理由的:他们可以在包含模板中引用任何内容。如果有模板模板参数,则必须将模板作为参数传递给它,而不是模板的实例化。换句话说,您传递的模板没有参数作为参数。
这意味着您的代码完全错误 - 您使用MyImpl
作为MyHub
的参数,但MyImpl
是类。 {{1需要一个模板,而不是一个类。 MyHub
的正确实例化将是MyHub
。并非在使用MyHub<MyInterface>
之后没有模板参数;我们传递模板本身,而不是它的实例化。
模板模板参数在实践中很少使用。如果要使用自己的类型实例化参数模板,则只能使用它们。所以我希望您的MyInterface
代码可以执行以下操作:
MyHub
这似乎不是你想要做的。我相信你想要一个普通的类型模板参数,并为它的template <template <class> class ImplTemplate>
struct MyHub
{
typedef ImplTemplate<SomeMyHub_SpecificType> TheType;
// ... use TheType
};
提供一个嵌套的typedef。像这样:
T