怎么能" min"类型可以在可变参数包中找到?

时间:2014-05-27 17:58:50

标签: c++ templates c++11 variadic-templates template-meta-programming

按“min”类型,我的意思是根据编译时函数比较 less 的类型,例如sizeof

我有一个draft implementation,会先出示它并提到我面临的两个问题:

#include <iostream>
#include <typeinfo>
#include <type_traits>

using namespace std;

//  Unspecialized version
template<typename...Ts>
struct Tmin
{ 
    using type = void;
};

template<typename T>
struct Tmin<T>
{
    using type = T;
};

template<typename T1, typename T2, typename...Ts>
struct Tmin<T1, T2, Ts...>
{
    using type = typename std::conditional<sizeof(T1) < sizeof(T2), 
        typename Tmin<T1, Ts...>::type, typename Tmin<T2, Ts...>::type
        >::type;
};

int main()
{
    cout << typeid(Tmin<float, int, double>::type).name() << endl;
    return 0;
}
  1. 这在VS2013中不起作用(发出fatal error C1075)。我是否使用任何非标准设施或是否有更符合标准的方式来编写上述内容?

  2. 假设我想使用sizeof以外的方法来比较类型。是否有一种consice方式/良好的设计能够将元函数作为比较器传递并且仍然保持使用sizeof的默认行为(在非指定的情况下)?

4 个答案:

答案 0 :(得分:2)

看起来MSVC正在搞砸解析std::conditional表达式。似乎认为sizeof(T1) < sizeof(T2)之间的差距小于另一个模板参数的开始<。添加一组额外的括号,它可以工作。

template<typename T1, typename T2, typename...Ts>
struct Tmin<T1, T2, Ts...>
{
    using type = typename std::conditional<(sizeof(T1) < sizeof(T2)), 
    //                                     ^                       ^
        typename Tmin<T1, Ts...>::type, typename Tmin<T2, Ts...>::type
        >::type;
};

对我来说看起来像是一个MSVC错误。

答案 1 :(得分:1)

如果您想使用不同的谓词,以下内容应该有效:

#include <type_traits>
#include <typeinfo>
#include <iostream>

template<template<typename,typename> class P, typename... Ts>
struct min_t_impl;

template<template<typename,typename> class P, typename T>
struct min_t_impl< P, T >
{
    using type = T;
};

template<template<typename,typename> class P, typename T, typename U, typename... Ts>
struct min_t_impl< P, T, U, Ts... >
{
    using V = typename std::conditional< P<T,U>::value, T, U >::type;
    using type = typename min_t_impl< P, V, Ts... >::type;
};

template<template<typename,typename> class P, typename... Ts>
using min_t = typename min_t_impl<P,Ts...>::type;

template<typename T,typename U>
using my_pred = std::integral_constant< bool, ( sizeof(T) <= sizeof(U) ) >;

int main()
{
    std::cout << typeid(min_t<my_pred, float, int, double>).name() << std::endl;
    return 0;
}

Live example

请注意,您需要小心使用如何递归。四种类型和您的版本的示例可能会产生以下所有实例:

Tmin<A,B,C,D>

Tmin<A,C,D>
Tmin<B,C,D>

Tmin<A,D>
Tmin<C,D>
Tmin<B,D>

Tmin<A>
Tmin<B>
Tmin<C>
Tmin<D>

虽然我的是线性的,但总共产生四个实例。你添加的参数越多,它变得越重要!

答案 2 :(得分:1)

以下使用visual:

#include <iostream>
#include <typeinfo>
#include <type_traits>

//  Unspecialized version
template <template <typename, typename> class Less, typename ... Ts>
struct Tmin;

template<template <typename, typename> class Less>
struct Tmin<Less>
{
    using type = void;
};

template<template <typename, typename> class Less, typename T>
struct Tmin<Less, T>
{
    using type = T;
};

template<template <typename, typename> class Less, typename T1, typename T2, typename...Ts>
struct Tmin<Less, T1, T2, Ts...>
{
private:
    using lower_type = typename std::conditional<Less<T1, T2>::value, T1, T2>::type;
public:
    using type = typename Tmin<Less, lower_type, Ts...>::type;
};


template <typename T1, typename T2> struct sizeofLess : std::integral_constant<bool, (sizeof(T1) < sizeof (T2))> {};


int main()
{
    std::cout << typeid(Tmin<sizeofLess, float, int, double>::type).name() << std::endl;
    return 0;
}

要拥有默认行为,您必须将原型更改为

template <typename Tuple, template <typename, typename> class Less = DefaultLess>
struct Tmin;

答案 3 :(得分:1)

首先,正如Praetorian所说,不编译肯定是一个MSVC错误。它在g ++和clang ++中完美地工作,即使没有括号。

其次,您可以将Tmin包装在另一个模板中(我称之为TTmin,是的,非常原创)并且您可以使用您需要的任何比较类:

#include <iostream>
#include <typeinfo>
#include <type_traits>

using namespace std;



template<typename T1, typename T2>
struct Tsmaller : std::integral_constant<bool, sizeof(T1) < sizeof(T2)> {
};

template<template<typename, typename> class Compare = Tsmaller> struct TTMin {

//  Unspecialized version
template<typename...Ts>
struct Tmin
{ 
    using type = void;
};

template<typename T>
struct Tmin<T>
{
    using type = T;
};


template<typename T1, typename T2, typename...Ts>
struct Tmin<T1, T2, Ts...>
{
    using type = typename std::conditional<Compare<T1, T2>::value, 
        typename Tmin<T1, Ts...>::type, typename Tmin<T2, Ts...>::type
        >::type;
};

};

int main()
{
    cout << typeid(TTMin<>::Tmin<float, int, double>::type).name() << endl;
    return 0;
}

link to live-at-coliru example