13

假设我在一个模板中,我想知道类型参数 T 是否是特定模板的实例化,例如std::shared_ptr

template<typename T>
void f(T&& param)
{
    if (instantiation_of(T, std::shared_ptr)) ...   // if T is an instantiation of 
                                                    // std::shared_ptr...
  ...
}

更有可能我想做这种测试作为 std::enable_if 测试的一部分:

template<typename T>
std::enable_if<instantiation_of<T, std::shared_ptr>::type
f(T&& param) 
{
    ...
}

// other overloads of f for when T is not an instantiation of std::shared_ptr

有没有办法做到这一点?请注意,该解决方案需要使用所有可能的类型和模板,包括标准库和其他我无法修改的库中的类型和模板。我对std::shared_ptr上面的使用只是我可能想做的一个例子。

如果这是可能的,我将如何自己编写测试,即实现instantiation_of

4

3 回答 3

11

为什么enable_if在简单的重载就足够时使用?

template<typename T>
void f(std::shared_ptr<T> param) 
{
    // ...
}

如果您确实需要这样的特性,我认为这应该可以帮助您入门(仅使用 VC++ 2010 进行了粗略测试):

#include <type_traits>

template<typename>
struct template_arg;

template<template<typename> class T, typename U>
struct template_arg<T<U>>
{
    typedef U type;
};

template<typename T>
struct is_template
{
    static T* make();

    template<typename U>
    static std::true_type check(U*, typename template_arg<U>::type* = nullptr);
    static std::false_type check(...);

    static bool const value =
        std::is_same<std::true_type, decltype(check(make()))>::value;
};

template<
    typename T,
    template<typename> class,
    bool Enable = is_template<T>::value
>
struct specialization_of : std::false_type
{ };

template<typename T, template<typename> class U>
struct specialization_of<T, U, true> :
    std::is_same<T, U<typename template_arg<T>::type>>
{ };
于 2012-05-30T17:40:42.270 回答
9

部分规范应该能够做到这一点。

template <template <typename...> class X, typename T>
struct instantiation_of : std::false_type {};

template <template <typename...> class X, typename... Y>
struct instantiation_of<X, X<Y...>> : std::true_type {};

http://ideone.com/4n346

我实际上不得不查找模板模板语法,因为我以前基本上从来没有使用过它。

不确定这如何与模板交互,例如std::vector与其他默认参数。

于 2012-05-30T17:46:07.297 回答
3

处理 T&& 时最好的方法是确保在进行检查之前 remove_reference ,因为基础类型 T 可以是引用或值类型,并且模板部分特化必须准确工作。结合代码上方的答案可以做到这一点:

template <
  typename T,
  template <typename...> class Templated
> struct has_template_type_impl : std::false_type {};

template <
  template <typename...> class T,
  typename... Ts
> struct has_template_type_impl<T<Ts...>, T> : std::true_type {};

template <
  typename T, 
  template <typename...> class Templated
> using has_template_type = has_template_type_impl<
    typename std::remove_reference<T>::type,
    Templated
>;

然后你只需 enable_if 你的胜利之路:

template <typename T>
typename std::enable_if<has_template_type<T, std::shared_ptr>::value>::type
f(T&& param)
{
  // ...
}
于 2012-05-30T18:35:40.620 回答