2015-02-24 57 views
11

所以我有这样的真丑代码:是否有这样的事情了模板化的case语句

template <typename T> 
std::conditional_t<sizeof(T) == sizeof(char), 
        char, 
        conditional_t<sizeof(T) == sizeof(short), 
           short, 
           conditional_t<sizeof(T) == sizeof(long), 
               long, 
               enable_if_t<sizeof(T) == sizeof(long long), 
                  long long>>>> foo(T bar){return reinterpret_cast<decltype(foo(bar))>(bar);} 

我使用嵌套conditional_t s到做各种各样的case语句。有没有什么能够更加优雅地完成这件事,还是我需要制作自己的模板化案例陈述?

注:其实我知道,这使用的reinterpret_cast不好:Why Doesn't reinterpret_cast Force copy_n for Casts between Same-Sized Types?

+1

这段代码试图实现什么? – Slava 2015-02-24 15:11:43

+0

你可以为char,short,int,long long做一个模板... – amchacon 2015-02-24 15:11:54

+0

为什么这感觉就像你的依赖类型编程语言之后? – 2015-02-24 15:12:20

回答

10

我不得不这样做一次,所以我写了一个small wrapper来实现结果的整齐。你可以使用它,如下所示(请参阅​​用于测试)

template<class T> 
typename static_switch<sizeof(T) 
      ,int // default case 
      ,static_case<sizeof(char),char> 
      ,static_case<sizeof(short),short> 
      ,static_case<sizeof(long),long> 
      >::type foo(T bar){ ... } 

它几乎做什么你已经在幕后,但通过包装它,我们把它(更多)可读。如果你需要的话,还有一个版本可以让你在类型T上切换direclty。

编辑:在@这里Deduplicator的建议是它背后

#include <type_traits> 

/* 
* Select a type based on the value of a compile-time constant such as a 
* constexpr or #define using static_switch. 
*/ 

template<int I,class T> 
struct static_case { 
    static constexpr int value = I; 
    using type = T; 
}; 

template<int I, class DefaultType, class Case1, class... OtherCases> 
struct static_switch{ 
    using type = typename std::conditional< I==Case1::value , 
        typename Case1::type, 
        typename static_switch<I,DefaultType,OtherCases...>::type 
        >::type; 
}; 

struct fail_on_default {}; 

template<int I, class DefaultType, class LastCase> 
struct static_switch<I,DefaultType,LastCase> { 
    using type = typename std::conditional< I==LastCase::value , 
        typename LastCase::type, 
        DefaultType 
        >::type; 

    static_assert(!(std::is_same<type, fail_on_default>::value), 
        "Default case reached in static_switch!"); 
}; 
+3

你可能想在这里从github导入你的代码......这将使答案完整。无论如何,我只是在写这样的东西,但你明白了。 – Deduplicator 2015-02-24 15:25:16

+0

@丹我不知道我懂得如何应用这个。如果你可以插入它,测试应该相当简单:'auto val = foo(13.0); static_assert(is_same :: value);' – 2015-02-24 15:25:19

+0

@JonathanMee:另外,如果值可以从类型派生,那么它可以被简化,就像你的情况一样。 – Deduplicator 2015-02-24 15:29:38

2

像这样的东西可能:

template <size_t N> struct SuitablySized; 

template<> struct SuitablySized<sizeof(char)> { 
    typedef char type; 
}; 
template<> struct SuitablySized<sizeof(short)> { 
    typedef short type; 
}; 
// Add more cases to taste 

template <typename T> 
typename SuitablySized<sizeof(T)>::type foo(T bar); 
+2

我们希望OP预先清除所有相同大小的类型... – Deduplicator 2015-02-24 15:22:37

4

switch语句的模板版本是一个专门的模板。

template<size_t n> struct matching_type; 
template<> struct matching_type<sizeof(char)> { typedef char type; }; 
template<> struct matching_type<sizeof(short)> { typedef short type; }; 
template<> struct matching_type<sizeof(int)> { typedef int type; }; 
template<> struct matching_type<sizeof(long)> { typedef long type; }; 
template<> struct matching_type<sizeof(long long)> { typedef long long type; }; 

template<typename T> 
matching_type<sizeof(T)>::type foo(T bar) 
{ 
    return reinterpret_cast<decltype(foo(bar))>(bar); 
} 
+4

希望OP预先清除所有相同大小的类型... – Deduplicator 2015-02-24 15:23:07

+0

请注意,在某些系统中,sizeof(int)可能等于sizeof( long)',这段代码不会被编译 – borisbn 2015-02-24 15:51:33

+2

是的,但'switch'语句有同样的问题! – 2015-02-24 16:27:51

3

只要你理解了风险的代码,同样大小的类型可能不是敞篷车,你可以简单地插件一个mpl::map ..

typedef map< 
     pair<int_<sizeof(char)>, char>, 
     pair<int_<sizeof(short)>, short>, 
     pair<int_<sizeof(int)>, int>, 
     pair<int_<sizeof(long long)>, long long> 
    > m; 

eg

#include <algorithm> 
#include <iostream> 

#include <boost/mpl/at.hpp> 
#include <boost/mpl/map.hpp> 

using namespace boost::mpl; 

typedef map< 
     pair<int_<sizeof(char)>, char>, 
     pair<int_<sizeof(short)>, short>, 
     pair<int_<sizeof(int)>, int>, 
     pair<int_<sizeof(long long)>, long long> 
    > m; 

template <typename T> 
typename at<m, int_<sizeof(T)>>::type foo(T bar) 
{ return reinterpret_cast<decltype(foo(bar))>(bar); } 


struct doh 
{ 
    std::string a, b, c; 
}; 

int main() 
{ 
    { 
     char c; 
     static_assert(std::is_same<decltype(foo(c)), char>::value, "error"); 
    } 
    { 
     short c; 
     static_assert(std::is_same<decltype(foo(c)), short>::value, "error"); 
    } 
    { 
     int c; 
     static_assert(std::is_same<decltype(foo(c)), int>::value, "error"); 
    } 
    { 
     long long c; 
     static_assert(std::is_same<decltype(foo(c)), long long>::value, "error"); 
    } 
    { 
     double c; 
     static_assert(std::is_same<decltype(foo(c)), long long>::value, "error"); 
    }  
    { 
     doh c; 
     static_assert(std::is_same<decltype(foo(c)), void_>::value, "error"); 
    }  
} 
+0

这看起来像一个有前途的解决方案。但我没有提升。我想知道这是否可以通过'std :: map'实现? – 2015-02-24 16:28:03

+1

@JonathanMee,不可能用'std :: map',你可以用'switch'来完成,但它会是一个运行时测试而不是编译时间... – Nim 2015-02-25 08:09:15

1

A型标签:

template<class T>struct tag{using type=T;}; 

void_t(即将在C++ 17的编译器,你附近):

template<class...>struct voider{using type=void;}; 
template<class...Ts>using void_t=typename voider<Ts...>::type; 

enable_first_t需要的std::enable_if一包(注意缺乏_t),并返回通过测试的第一个。您可以使用tag<X>更换std::enable_if<true, X>

template<class T,class=void>struct has_type:std::false_type{}; 
template<class T>struct has_type<T, void_t<typename T::type>>:std::true_type{}; 

namespace details { 
    template<class, class...Ts> 
    struct enable_first {}; 
    template<class T0, class...Ts> 
    struct enable_first<std::enable_if_t< !has_type<T0>{} >, T0, Ts... >:enable_first<void, Ts...> {}; 
    template<class T0, class...Ts> 
    struct enable_first<std::enable_if_t< has_type<T0>{} >, T0, Ts...>:T0 {}; 
} 

template<class...Ts>using enable_first_t=typename details::enable_first<void, Ts...>::type; 

template<class T> 
using result = enable_first_t< 
    std::enable_if<sizeof(T)==sizeof(char), char>, 
    std::enable_if<sizeof(T)==sizeof(short), short>, 
    std::enable_if<sizeof(T)==sizeof(long), long>, 
    tag<int> // default 
>; 

这种行为很像0​​,但语句是完全布尔表达式。

live example

+0

为什么不使用'template void_t =无效;'? – dyp 2015-02-24 23:20:53

相关问题