使用模板从类型列表提升类型

Promote type from a list of types, with templates

本文关键字:类型 列表      更新时间:2023-10-16

我有一个带有int元素的vector和一个带有float元素的vector。在这种情况下,大多数首选类型是float,在点积中,我想返回float类型(如果没有指定)。

下面的代码就是这样做的,但是模板包出了问题。

你能帮我一点忙吗?

#include <iostream>
#include <vector>
#include <array>
using namespace std;

template<typename Tp, typename T1> struct contains
{
    constexpr static bool value = std::is_same<Tp, T1>::value;
};
template<typename Tp, typename T1, typename ... Tn> struct contains
{
    constexpr static bool value = std::is_same<Tp, T1>::value || contains<Tp, Tn...>::value;
};
template<typename ... T> struct perfect
{
    typedef 
        typename std::conditional<contains<long double, T...>::value, long double,
        typename std::conditional<contains<double     , T...>::value, double,
        typename std::conditional<contains<float      , T...>::value, float,
        typename std::conditional<contains<long long  , T...>::value, long long,
        typename std::conditional<contains<unsigned long long, T...>::value, unsigned long long,
        typename std::conditional<contains<int        , T...>::value, int,
        typename std::conditional<contains<unsigned int, T...>::value, unsigned int,
        //.....
        void
        >>>>>>>::type type;
};

struct Vector1 : public std::vector<double> {};
struct Vector2 : public std::vector<int> {};
struct Vector3 : public std::vector<float> {};
template<typename C1, typename C2, typename T = perfect<typename C1::value_type, typename C2::value_type>::type>
T dot_product(const C1 &c1, const C2 &c2)
{
    return 0; // return c1 * c2
} 
int main()
{
    Vector1 a;
    Vector2 b;
    cout << dot_product(a, b) << endl;
    cout << dot_product<Vector1, Vector2, long double>(a, b) << endl;
}

你错过了两件事。

template<typename Tp, typename T1> struct contains
{
    constexpr static bool value = std::is_same<Tp, T1>::value;
};

专门化,所以应该是

template<typename Tp, typename T1> struct contains<T1,Tp>
                                               // ^^^^^^ 
{
    constexpr static bool value = std::is_same<Tp, T1>::value;
};

,应该在原模板之后定义


接下来,您在这里缺少了typename。

template<typename C1, typename C2, typename T = typename perfect<typename C1::value_type, typename C2::value_type>::type>
                                             // ^^^^^^^ 

然而,我应该提一下,你可能在这里把它复杂化了。我不确定这一切是否有必要从两种类型中推导出来。也许预处理宏可以为您做得更好。我假设这是一次练习。



编辑:
这是一个类似的操作,但不同的方法,从c++模板完整指南。老了,但仍然足够你的选择

#define MK_PROMOTION(T1,T2,Tr)             
    template<> class Promotion<T1, T2> {   
      public:                              
        typedef Tr type;                   
    };                                     
                                           
    template<> class Promotion<T2, T1> {   
      public:                              
        typedef Tr type;                   
    };

template<typename T1, typename T2>
class Promotion {
public:
    typedef T1 type;    
};

template<typename T>
class Promotion<T,T> {
  public:
    typedef T type;
};
MK_PROMOTION(int, char, int)
MK_PROMOTION(double, float, double)
MK_PROMOTION(double, int, double)


typedef std::vector<double> Vector1;
typedef std::vector<int> Vector2;
typedef std::vector<float> Vector3;

template<typename C1, typename C2, typename T = typename Promotion< typename C1::value_type, typename C2::value_type >::type >
T dot_product(const C1 &c1, const C2 &c2)
{
    return 0; // return c1 * c2
} 
int main()
{
    Vector1 a;
    Vector2 b;
    cout << dot_product(a, b) << endl;
    cout << dot_product<Vector1, Vector2, long double>(a, b) << endl;
}

你要找的是decltype<C1() * C2()>,不需要你的struct perfect

编辑: decltype()它更好。

template<typename C1, typename C2, typename T = decltype(typename C1::value_type() * typename C2::value_type())>
T dot_product(const C1 &c1, const C2 &c2) { return 5; }

修正了未来社区需要的程序:(许多语法错误)

#include <iostream>
#include <vector>
using namespace std;
template<typename Tp, typename T1, typename ... Tn> struct contains_type
    { constexpr static bool value = std::is_same<Tp, T1>::value || contains_type<Tp, Tn...>::value; };
template<typename Tp, typename T1> struct contains_type<Tp, T1>
    { constexpr static bool value = std::is_same<Tp, T1>::value; };
template<typename ... T> struct type_promotion
{
    typedef typename
        std::conditional<contains_type<long double, T...>::value, long double,
        typename std::conditional<contains_type<double     , T...>::value, double,
        typename std::conditional<contains_type<float      , T...>::value, float,
        typename std::conditional<contains_type<long long  , T...>::value, long long,
        typename std::conditional<contains_type<unsigned long long, T...>::value, unsigned long long,
        typename std::conditional<contains_type<int        , T...>::value, int,
        typename std::conditional<contains_type<unsigned int, T...>::value, unsigned int,
        void>::type>::type>::type>::type>::type>::type>::type type;
};

struct Vector1 : public std::vector<double> {};
struct Vector2 : public std::vector<int> {};
template<typename C1, typename C2, typename T = typename type_promotion<typename C1::value_type, typename C2::value_type>::type>
T dot_product(const C1 &c1, const C2 &c2)
    { return 5; } 
int main()
{
    Vector1 a;
    Vector2 b, c;
    cout << dot_product(a, b) / 2 << endl;
    cout << dot_product(b, c) / 2 << endl;
    cout << dot_product<Vector1, Vector2, long double>(a, b) << endl;
}