【问题标题】:How to use 'default' value within template metaprogramming如何在模板元编程中使用“默认”值
【发布时间】:2014-02-06 12:15:52
【问题描述】:

我面临以下问题:

我有 some 通用容器,它能够对类型进行 some 操作。为简单起见,这些操作在请求时是线程安全的。并且,requested to表示容器中的类型有typedef std::true_type needs_thread_safety;

struct thread_safe_item {
    typedef std::true_type needs_thread_safety;
    /* */ 
};

struct thread_unsafe_item {
    typedef std::false_type needs_thread_safety;
    /* */
};
template<typename TItem> container {
    /* some algorithms, that are std::enable_if selected, according to needs_thread_safety */
};

但是,我希望 needs_thread_safety 选择加入,并且不需要定义(= 默认 false_type)。我试过以下:

    struct thread_unsafe_item {
        /* */ 
    };

template<typename TItem>
struct thread_safety_selector
{
    template<typename T>
    struct has_defined_thread_safety
    {
        typedef char yes[1];
        typedef char no[2];

        template <typename C> static yes& test(typename C::needs_thread_safety*);
        template <typename> static no& test(...);

        static const bool value = sizeof(test<T>(0)) == sizeof(yes);
    };

    typedef 
        typename std::conditional<
            has_defined_thread_safety<TItem>::value,
            typename TItem::needs_thread_safety,
            std::false_type
        >::type needs_thread_safety;
};
....
struct <typename TItem> container {
    /* changed all TItem::needs_thread_safety selectors to thread_safety_selector<TItem>::needs_thread_safety */
};

但显然没有进行惰性评估,因为错误是error C2039: 'needs_thread_safety' : is not a member of 'thread_unsafe_item'

如何实现未指定参数的默认值?

这是出于教育目的,所以我不需要不同的方法来解决这个问题。

谢谢!

【问题讨论】:

  • 通常我使用类型选择器来指定我的最终类的特定基类,其中基类包含适当的实现。

标签: c++ templates c++11 metaprogramming


【解决方案1】:

您不能为此使用std::conditional,因为它总是会解析其所有参数。您可以创建自己的谓词:

template <bool, class>
struct get_thread_safety;

template <class T>
struct get_thread_safety<true, T>
{
  typedef typename T::needs_thread_safety type;
};

template <class T>
struct get_thread_safety<false, T>
{
  typedef std::false_type type;
};

// Used like this:

typedef 
    typename get_thread_safety<
        has_defined_thread_safety<TItem>::value,
        TItem
    >::type needs_thread_safety;

【讨论】:

  • +1,但也可以使用std::conditional
【解决方案2】:

实际上,使用std::enable_ifstd::conditional 可以更轻松地完成:

#include <iostream>
#include <type_traits>

// Classes to be checked against needs_thread_safety
struct A {};
struct B { typedef std::true_type needs_thread_safety; };
struct C { typedef std::false_type needs_thread_safety; };

// Checker helper
template<class T> class get_thread_safety
{
    typedef char(&zero_size_t)[0];

    template <class X> static typename std::enable_if<X::needs_thread_safety::value, char>::type check(int);
    template <class X> static typename std::enable_if<!X::needs_thread_safety::value, zero_size_t>::type check(int);
    template <class X> static zero_size_t check(...);

public:
    typedef typename std::conditional<sizeof(check<T>(0)), std::true_type, std::false_type>::type type;
};

int main()
{
   // Usage. Will print 0 1 0
   std::cout << get_thread_safety<A>::type::value << std::endl;     
   std::cout << get_thread_safety<B>::type::value << std::endl;
   std::cout << get_thread_safety<C>::type::value << std::endl; 

   return 0;
}

【讨论】:

    【解决方案3】:

    您实际上可以以一种懒惰的方式使用std::conditional,您只需要避免在其模板参数列表中使用嵌套的typedef。对于false 案例,您还需要另一种回退类型(“默认值”,正如您所说的那样):

    template<typename TItem>
    struct thread_safety_selector
    {
        template<typename T>
        struct has_defined_thread_safety
        {
            typedef char yes[1];
            typedef char no[2];
    
            template <typename C> static yes& test(typename C::needs_thread_safety*);
            template <typename> static no& test(...);
    
            static const bool value = sizeof(test<T>(0)) == sizeof(yes);
        };
    
        // this would be your "default value"
        struct not_thread_safe {
            typedef std::false_type needs_thread_safety;
        };
    
        typedef
            typename std::conditional<
                has_defined_thread_safety<TItem>::value,
                TItem,   // <---- note, not using the typedef here
                not_thread_safe
            >::type::needs_thread_safety  needs_thread_safety;
         //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
         //  lazily, after the selection is done
    };
    

    【讨论】:

    • 您可以使用std::true_typestd::false_type 作为返回类型,而不是yesno(以及sizeof)(如果需要,可以使用decltype(test&lt;T&gt;(0))::value)。
    猜你喜欢
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    相关资源
    最近更新 更多