[英]Is it possible to specialize a template definition based on the existence of a nested typedef of a template type parameter?
I have a template, template <typename T> class wrapper
, that I would like to specialize based on the existence of typename T::context_type
. 我有一个模板,
template <typename T> class wrapper
,我想基于typename T::context_type
的存在来专门化。 If typename T::context_type
is declared, then the constructors and assignment operator overloads of the wrapper<T>
instantiation should accept a mandatory typename T::context_type
parameter. 如果声明了
typename T::context_type
,那么wrapper<T>
实例化的构造函数和赋值运算符重载应该接受强制typename T::context_type
参数。 Additionally, wrapper<T>
objects would store "context" in the member data. 此外,
wrapper<T>
对象将在成员数据中存储“上下文”。 If typename T::context_type
does not exist, then the constructors and assignment operator overloads of wrapper<T>
would take one less parameter and there would be no additional data member. 如果
typename T::context_type
不存在,则wrapper<T>
的构造函数和赋值运算符重载将减少一个参数,并且不会有其他数据成员。
Is this possible? 这可能吗? Can I get the following code to compile without changing the definitions of
config1
, config2
, and main()
? 我是否可以在不更改
config1
, config2
和main()
的定义的情况下编译以下代码?
#include <iostream>
template <typename T, bool context_type_defined = true>
class wrapper
{
public:
typedef typename T::context_type context_type;
private:
context_type ctx;
public:
wrapper(context_type ctx_)
: ctx(ctx_)
{
std::cout << "T::context_type exists." << std::endl;
}
};
template <typename T>
class wrapper<T, false>
{
public:
wrapper() {
std::cout << "T::context_type does not exist." << std::endl;
}
};
class config1 {
public:
typedef int context_type;
};
class config2 {
public:
};
int main()
{
wrapper<config1> w1(0);
wrapper<config2> w2;
}
Yes, it is possible. 对的,这是可能的。 I have implemented such behavior in the past by using some metaprogramming tricks.
我过去通过使用一些元编程技巧实现了这种行为。 The basic build blocks are:
基本构建块是:
BOOST_MPL_HAS_XXX_TRAIT_DEF
, to define a metafunction predicate that will evaluate to a true type if the argument is of class type and has a nested type with a given name (context_type in your case). BOOST_MPL_HAS_XXX_TRAIT_DEF
,用于定义元函数谓词,如果参数是类类型并且具有给定名称的嵌套类型(在您的情况下为context_type),则将评估为真实类型。
http://www.boost.org/doc/libs/1_47_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html http://www.boost.org/doc/libs/1_47_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html
Boost.EnableIf
, to define the specializations based on the previously defined trait. Boost.EnableIf
,根据先前定义的特征定义特化。
http://www.boost.org/libs/utility/enable_if.html # See 3.1 Enabling template class specializations http://www.boost.org/libs/utility/enable_if.html#请参阅3.1启用模板类专业化
Note that you may be able to get that behavior working directly with SFINAE, something like this may work: 请注意,您可以直接使用SFINAE获取该行为,这可能会起作用:
template< typename T, typename Context = void >
class wrapper { ... }; // Base definition
template< typename T >
class wrapper< T, typename voif_mfn< typename T::context_type >::type > { ... }; // Specialization
However, I like the expressiveness of the solution based on traits and enable if. 但是,我喜欢基于特征的解决方案的表现力,并启用if。
That's possible, and there are many ways to implement this. 这是可能的,有很多方法可以实现这一点。 All of them should go back on some trait class
has_type
so that has_type<T>::value
is true if the member typedef exists, and false otherwise. 所有这些都应该返回一些特征类
has_type
以便如果成员typedef存在则has_type<T>::value
为true,否则为false。 Let's assume we have this trait class already. 我们假设我们已经有了这个特质类。 Then here's one solution, using C++11 template aliases:
然后这是一个使用C ++ 11模板别名的解决方案:
template <typename T, bool> class FooImpl
{
// implement general case
};
template <typename T> class FooImpl<T, true>
{
// implement specific case
};
template <typename T> using Foo = FooImpl<T, has_type<T>::value>; // C++11 only
Now to make the typetrait: 现在来制作typetrait:
template<typename T>
struct has_type
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template<typename C> static yes test(typename C::context_type*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
If you don't have C++11, or if you don't want to rewrite the entire class, you can make the distinction more fine-grained, eg by using std::enable_if
, std::conditional
, etc. Post a comment if you want some specific examples. 如果您没有C ++ 11,或者您不想重写整个类,则可以使区分更精细,例如使用
std::enable_if
, std::conditional
等。如果你想要一些具体的例子,请评论。
Using @K-ballo's answer , I wrote the following: 使用@ K-ballo的答案 ,我写了以下内容:
namespace detail {
BOOST_MPL_HAS_XXX_TRAIT_DEF(context_type)
}
template <typename T, typename Enable = void>
class wrapper
{
public:
wrapper() {
std::cout << "T::context_type does not exist." << std::endl;
}
};
template <typename T>
class wrapper<T, typename boost::enable_if<detail::has_context_type<T> >::type>
{
public:
typedef typename T::context_type context_type;
private:
context_type ctx;
public:
wrapper(context_type ctx_)
: ctx(ctx_)
{
std::cout << "T::context_type exists." << std::endl;
}
};
Now, the sample code compiles and outputs: 现在,示例代码编译并输出:
T::context_type exists. T::context_type does not exist.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.