我可以为缺少的模板成员类型创建默认类型吗?

时间:2014-02-03 13:49:09

标签: c++ templates

如果我有一个带有模板参数的算法,比如

struct DemoParameters
{
    typedef float Price;
    typedef std :: list <Price> Prices;
}

template <typename Parameters>
void foo (int arg)
{
    typename Parameters :: Prices prices = ...;
    // blah
}

foo <DemoParameters> (123);

有没有办法可以写foo,这样如果Parameters缺少某些内容,我就可以提供默认值。例如

struct PartialParameters
{
     typedef float Price;
     // Prices is missing
}

template <typename Parameters>
void foo (int arg)
{
    Prices_type<Parameters>::type prices = ...;
}

foo<DemoParameters>    (123); // will use list<Price>
foo<PartialParameters> (123); // will use vector<Price>

如果Prices_type<Parameters>::typeParameters::Prices的成员,PricesParameters,则std::vector<Parameters::Price>为{{1}}。

这可能吗?

2 个答案:

答案 0 :(得分:1)

这名为SFINAE:

#include <iostream>

struct Foo {
    using Type = int;
};
struct Bar {
};

template <typename T, typename Default >
struct TypeOrDefault {
    template <typename U>
    static auto call( int ) -> typename U::Type;

    template <typename U>
    static auto call(...) -> Default;

    using type = decltype( call<T>( 1 ) );
};

int main() {
    std::cout << std::is_same<int,typename TypeOrDefault<Foo,float>::type > ::value << std::endl;
    std::cout << std::is_same<int,typename TypeOrDefault<Bar,float>::type > ::value << std::endl;
}

上面的示例为Foo提供type int TypeOrDefault类型成员,为Bar提供float。

您还可以使用模板别名简化使用语法。

template < typename T, typename Default >
using TypeOrDefaultType = typename TypeOrDefault<T,Default>::type;

然后

int main() {
        std::cout << std::is_same<int,TypeOrDefaultType<Foo,float> > ::value << std::endl;
        std::cout << std::is_same<int,TypeOrDefaultType<Bar,float> > ::value << std::endl;
    }

答案 1 :(得分:1)

你可以这样做(标签调度和SFINAE):

template <typename T> struct has_Prices
{
private:
    template <typename U> static std::uint8_t check(typename U::Prices*);
    template <typename U> static std::uint16_t check(...);
public:
    static const bool value = sizeof(check<T>(0)) == sizeof(std::uint8_t);
};

template <typename T, bool = has_Prices<T>::value> struct Prices_type;

template <typename T>
struct Prices_type<T, true>
{
    typedef typename T::Prices type;
};

template <typename T, bool>
struct Prices_type
{
    typedef std::vector<typename T::Price> type;
};

测试它:

struct DemoParameters
{
    typedef float Price;
    typedef std :: list <Price> Prices;
};

struct PartialParameters
{
     typedef float Price;
     // Prices is missing
};

static_assert(std::is_same<std::list<float>, Prices_type<DemoParameters>::type>::value, "");
static_assert(std::is_same<std::vector<float>, Prices_type<PartialParameters>::type>::value, "");