C ++基于其他模板参数的Deduce模板参数

时间:2013-02-22 13:49:33

标签: c++ templates

假设我有以下课程:

template <class T, class U, class V> Foo
{
    ...
};

模板参数具有不同的映射,因此我可以根据T是什么来推断其他模板参数U和V.例如,如果T为double,则U和V将始终为某些类D1和D2,如果T为float,则U和V将始终为其他类F1和F2。

考虑到这一点,有没有一种方法可以只传入一个模板参数,并让编译器推导出其他两个参数?

我知道简单的答案就是将这些其他类也模板化并将模板参数T传递给它们,但是我无法将这些类模板化(它们是由工具自动生成的)。 / p>

理想情况下,我可以像这样使用typedef或#define:

typedef Foo<double> Foo<double, D1, D2>
typedef Foo<float> Foo<float, F1, F2>

但是这些不能编译。我想知道是否有办法使用模板元编程或模板模板参数来解决这个问题,但我似乎无法将这些概念包裹起来,我有一种直觉,那里可能有更简单的答案。有人有什么想法吗?

2 个答案:

答案 0 :(得分:6)

你可以摆脱UV,就像这样:

template <typename T>
struct Foo
{
  typedef typename deduce_from<T>::U U;
  typedef typename deduce_from<T>::V V;
};

其中deduce_from封装了演绎过程。

答案 1 :(得分:6)

Angew给出的答案向您展示了正确的方法,但未向您展示如何应对UV无法推断且必须提供的情况通过实例化客户端。

要处理这种情况,您可以为模板参数UV分配默认参数:

struct D1 { }; struct D2 { };
struct F1 { }; struct F2 { };

// Primary template
template<typename T>
struct deduce_from
{
};

// Specialization for double: U -> D1, V -> D2
template<>
struct deduce_from<double>
{
    typedef D1 U;
    typedef D2 V;
};

// Specialization for float: U -> F1, V -> F2
template<>
struct deduce_from<float>
{
    typedef F1 U;
    typedef F2 V;
};

// Give defaults to U and V: if deduce_from is not specialized for
// the supplied T, and U or V are not explicitly provided, a compilation
// error will occur 
template<
    typename T,
    typename U = typename deduce_from<T>::U,
    typename V = typename deduce_from<T>::V
    >
struct Foo
{
    typedef U typeU;
    typedef V typeV;
};

这是一个测试上述解决方案正确性的简单程序:

#include <type_traits>

int main()
{
    static_assert(std::is_same<Foo<double>::typeU, D1>::value, "Error!");
    static_assert(std::is_same<Foo<double>::typeV, D2>::value, "Error!");
    static_assert(std::is_same<Foo<float>::typeU, F1>::value, "Error!");
    static_assert(std::is_same<Foo<float>::typeV, F2>::value, "Error!");

    // Uncommenting this will give you an ERROR! 
    // No deduced types for U and V when T is int
    /* static_assert(
        std::is_same<Foo<int>::typeU, void>::value, "Error!"
        ); */
    static_assert(
        std::is_same<Foo<int, bool, char>::typeU, bool>::value, "Error!"
        ); // OK
    static_assert(
        std::is_same<Foo<int, bool, char>::typeV, char>::value, "Error!"
        ); // OK
}