我有一个模板template <typename T> class wrapper
,我希望根据typename T::context_type
的存在来专门化。如果声明了typename T::context_type
,那么wrapper<T>
实例化的构造函数和赋值运算符重载应该接受强制typename T::context_type
参数。此外,wrapper<T>
个对象会在成员数据中存储“上下文”。如果typename T::context_type
不存在,则wrapper<T>
的构造函数和赋值运算符重载将减少一个参数,并且不会有其他数据成员。
这可能吗?我是否可以在不更改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;
}
答案 0 :(得分:4)
是的,有可能。我过去通过使用一些元编程技巧实现了这种行为。基本构建块是:
BOOST_MPL_HAS_XXX_TRAIT_DEF
,用于定义一个元函数谓词,如果参数是类类型并且具有给定名称的嵌套类型(在您的情况下为context_type),则该元函数谓词将计算为true类型。
http://www.boost.org/doc/libs/1_47_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html
Boost.EnableIf
,根据先前定义的特征定义特化。
http://www.boost.org/libs/utility/enable_if.html#请参阅3.1启用模板类专业化
请注意,您可以直接使用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
但是,我喜欢基于特征的解决方案的表现力,并启用if。
答案 1 :(得分:4)
这是可能的,有很多方法可以实现这一点。所有这些都应该返回一些特征类has_type
,这样如果成员typedef存在,则has_type<T>::value
为真,否则为false。我们假设我们已经有了这个特质类。然后这是一个使用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
现在制作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);
};
如果你没有C ++ 11,或者你不想重写整个课程,你可以使区别更精细,例如:使用std::enable_if
,std::conditional
等。如果您想要一些具体示例,请发表评论。
答案 2 :(得分:1)
使用@K-ballo's answer,我写了以下内容:
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;
}
};
现在,示例代码编译并输出:
T::context_type exists. T::context_type does not exist.