是否可以根据模板类型参数的嵌套 typedef 的存在来专门化模板定义?

发布于 2024-12-06 13:55:21 字数 1171 浏览 0 评论 0原文

我有一个模板, template;类包装器,我想根据typename T::context_type的存在进行专门化。如果声明了 typename T::context_type,则包装器实例化的构造函数和赋值运算符重载应接受强制的 typename T::context_type< /代码> 参数。此外,wrapper对象将在成员数据中存储“上下文”。如果 typename T::context_type 不存在,则 wrapper 的构造函数和赋值运算符重载将少一个参数,并且不会有额外的数据成员。

这可能吗?我可以在不更改 config1config2main() 定义的情况下编译以下代码吗?

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

I have a template, template <typename T> class wrapper, that I would like to specialize based on the existence of 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. Additionally, wrapper<T> objects would store "context" in the member data. 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.

Is this possible? Can I get the following code to compile without changing the definitions of config1, config2, and 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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寂寞美少年 2024-12-13 13:55:21

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

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

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).

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.

http://www.boost.org/libs/utility/enable_if.html # See 3.1 Enabling template class specializations


Note that you may be able to get that behavior working directly with SFINAE, something like this may work:

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.

夏の忆 2024-12-13 13:55:21

这是可能的,并且有很多方法可以实现这一点。所有这些都应该返回到某个特征类 has_type ,以便如果成员 typedef 存在,则 has_type::value 为 true,否则为 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,或者如果你不想重写整个类,你可以使区分更精细-grained,例如使用 std::enable_ifstd::conditional 等。如果您想要一些具体示例,请发表评论。

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. Let's assume we have this trait class already. Then here's one solution, using C++11 template aliases:

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:

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, e.g. by using std::enable_if, std::conditional, etc. Post a comment if you want some specific examples.

酒儿 2024-12-13 13:55:21

使用 @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 exists.
T::context_type does not exist.

Using @K-ballo's answer, I wrote the following:

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文