5

我有一个模板,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代码config2main()

#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;
}
4

3 回答 3

4

是的,有可能。我过去通过使用一些元编程技巧实现了这种行为。基本构建块是:

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

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 的解决方案的表现力。

于 2011-09-27T21:39:26.813 回答
4

这是可能的,并且有很多方法可以实现这一点。所有这些都应该回到某个特征类has_typehas_type<T>::value如果成员 typedef 存在则为真,否则为假。假设我们已经有了这个 trait 类。然后这是一个解决方案,使用 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

现在制作类型:

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等。如果您需要一些具体示例,请发表评论.

于 2011-09-27T21:53:13.063 回答
1

使用@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;
    }
};

现在,示例代码编译并输出:

T::context_type 存在。
T::context_type 不存在。
于 2011-09-27T22:51:01.883 回答