更好的模式为部分专业化消歧优先级链? [英] Better pattern for partial specialization disambiguation precedence chain?

查看:165
本文介绍了更好的模式为部分专业化消歧优先级链?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下系列的部分特化:

  template< typename T,typename Enable = void> 
struct foo {
void operator()()const {cout< 非特化<< endl; }
};

template< typename T>
struct foo< T,enable_if_t<
is_integral< T> :: value
>> {
void operator()()const {cout< is_integral< endl; }
};

template< typename T>
struct foo< T,enable_if_t<
sizeof(T)== 4
而不是is_integral< T> :: value
>> {
void operator()()const {cout< size 4<< endl; }
};

template< typename T>
struct foo< T,enable_if_t<
is_fundamental< T> :: value
而不是(sizeof(T)== 4)
,而不是is_integral< T> :: value
> $ b void operator()()const {cout< 基本< endl; }
};

// etc ...

现场演示



我看到这种事情,确实, href =http://stackoverflow.com/a/26733643/152060>另一个StackOverflow回答在其他地方给同样的模式类似的问题)。虽然这样做,但是这个代码具有一些严重的可维护性问题,并且如果上述代码在库中,也排除了例如更高优先级的用户级部分专门化。什么是表达这个想法的更好的模式?我觉得有必要的东西(可能涉及继承和可变参数模板参数?),可以表达这个想法更干净和可维护。 (假设每个专业都是一个全开的类,而不是一个简单的函子,所以重载的函数不能以简单的方式工作)。

解决方案

为什么我回答自己的问题



所以我自从提出这个问题以来,与原来的答案。经过很多的fiddling和试错/错误,我想出了一个模式,我使用标签调度更快乐。无论它是否比以前的答案实际上更好,更可读,更可维护是为你判断,但我喜欢它更好。随意分开,批评它,并打破它。 : - )



基本版



下面是解决最简单版本问题

 模板< typename> struct always_true:true_type {}; 
template< typename> struct always_false:false_type {};

template< typename T,template< class ...> class condition = always_false,
typename flag = integral_constant< bool,condition< T> :: value>
>
struct foo;

////////////////////////////////////////
//unspecializedversion

//将always_true和false_type一起放在这里,这样没有人会意外地到达这里
template< typename T,typename true_or_false_type>
struct foo< T,always_true,true_or_false_type> {
void operator()()const {cout< 非特化<< endl; }
};

////////////////////////////////////////
// is_fundamental

template< typename T>
struct foo< T,is_fundamental,true_type> {
void operator()()const {cout< is_fundamental< endl; }
};
template< typename T> struct foo< T,is_fundamental,false_type> :foo< T,always_true> {};

////////////////////////////////////////
// is_integral

template< typename T>
struct foo< T,is_integral,true_type> {
void operator()()const {cout< is_integral< endl; }
};
template< typename T>
struct foo< T,is_integral,false_type> :foo< T,is_fundamental> {};

////////////////////////////////////////
// sizeof(T)== 4

template< typename T>
using size_is_4 = integral_constant< bool,sizeof(T)== 4> ;;

template< typename T>
struct foo< T,size_is_4,true_type> {
void operator()()const {cout< size_is_4< endl; }
};
template< typename T>
struct foo< T,size_is_4,false_type> :foo< T,is_integral> {};

////////////////////////////////////////
//现在把最专门的条件放在这个模板的基础中

template< typename T,typename true_or_false_type>
struct foo< T,always_false,true_or_false_type> :foo< T,size_is_4> {};

在上一个答案中的帮助结构中保存的优先级链在继承中进行编码。 / p>

更多钟声和哨声



添加能够使用户优先级高于图书馆的用户部分专业化多做一点,但原则是一样的。此演示中的完整版本。


Consider the following series of partial specializations:

template <typename T, typename Enable=void>
struct foo {
  void operator()() const { cout << "unspecialized" << endl; }
};

template <typename T>
struct foo<T, enable_if_t<
  is_integral<T>::value
>>{
  void operator()() const { cout << "is_integral" << endl; }
};

template <typename T>
struct foo<T, enable_if_t<
  sizeof(T) == 4
    and not is_integral<T>::value
>>{
  void operator()() const { cout << "size 4" << endl; }
};

template <typename T>
struct foo<T, enable_if_t<
  is_fundamental<T>::value
    and not (sizeof(T) == 4)
    and not is_integral<T>::value
>>{
  void operator()() const { cout << "fundamental" << endl; }
};

// etc...   

Live Demo

I see this kind of thing all of the time (indeed, another StackOverflow answer elsewhere gives the same pattern for a similar problem). While this works, this code has some serious maintainability issues, and also precludes, e.g., user-level partial specializations at higher priority if the above code is in a library. What's a better pattern for expressing this idea? I feel like there has to be something (maybe involving inheritance and variadic template parameters?) that can express this idea more cleanly and maintainably. (Suppose also that each of the specializations is a full-on class rather than a simple functor, so overloaded functions don't work in a simplistic way).

解决方案

Why am I answering my own question

So I've been bugged by this ever since asking this question, and I was never completely satisfied with the original answer. After much fiddling and trial/error, I've come up with a pattern I'm much happier with that uses tag dispatch. Whether or not it's actually better, more readable, and more maintainable than the previous answer is for you to judge, but I like it better. Feel free to pick it apart, criticize it, and break it. :-)

The Basic Version

Without further ado, here's the code that solve the simplest version of the problem

template <typename> struct always_true : true_type { };
template <typename> struct always_false : false_type { };

template <typename T, template <class...> class condition=always_false,
  typename flag=integral_constant<bool, condition<T>::value>
>
struct foo;

////////////////////////////////////////
// "unspecialized" version

// put always_true and false_type together here so that no one gets here accidentally
template <typename T, typename true_or_false_type>
struct foo<T, always_true, true_or_false_type> {
  void operator()() const { cout << "unspecialized" << endl; }
};

////////////////////////////////////////
// is_fundamental

template <typename T>
struct foo<T, is_fundamental, true_type> {
  void operator()() const { cout << "is_fundamental" << endl; }
};
template <typename T> struct foo<T, is_fundamental, false_type> : foo<T, always_true> { };

////////////////////////////////////////
// is_integral

template <typename T>
struct foo<T, is_integral, true_type> {
  void operator()() const { cout << "is_integral" << endl; }
};
template <typename T>
struct foo<T, is_integral, false_type> : foo<T, is_fundamental> { };

////////////////////////////////////////
// sizeof(T) == 4

template <typename T>
using size_is_4 = integral_constant<bool, sizeof(T) == 4>;

template <typename T>
struct foo<T, size_is_4, true_type> {
  void operator()() const { cout << "size_is_4" << endl; }
};
template <typename T>
struct foo<T, size_is_4, false_type> : foo<T, is_integral> { };

////////////////////////////////////////
// Now put the most specialized condition in the base of this template

template <typename T, typename true_or_false_type>
struct foo<T, always_false, true_or_false_type> : foo<T, size_is_4> { };

The chain of precedence, held in a helper struct in the previous answer, is encoded in inheritance.

More bells and whistles

Adding the ability to enable user partial specializations with higher precedence than the library ones takes a little more doing, but the principle is the same. The full version in this demo.

这篇关于更好的模式为部分专业化消歧优先级链?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆