【问题标题】:Template method specialization for multiple types多种类型的模板方法特化
【发布时间】:2015-10-29 18:19:48
【问题描述】:

我有一个类“A”,它公开了模板方法 foo。 Foo 有一个标准的实现,可以很好地与 B、C 配合使用。它还有一个针对 D 的特殊实现。

class A
{
  template<typename T>
  void foo()
  {
    //standard implementation
  }

  template<>
  void foo<D>
  {
    //special implementation
  }
}

class B{};
class C{};
class D{};

int main()
{
  A<B> a1;
  A<C> a2;
  A<D> a3;
}

现在,我需要添加类 E,它要求“foo”与 D 具有相同的特殊实现。 有没有办法这样说:对于所有类型都使用标准 foo.对于 D、E(等等)的特殊实现。

class A
{
  template<typename T>
  void foo()
  {
    //standard implementation
  }

  template<>
  void foo<D && E>  <-- PseudoCode - It doesn't work
  {
    //special implementation
  }
}

class B{};
class C{};
class D{};
class E{};

int main()
{
  A<B> a1;
  A<C> a2;
  A<D> a3;
  A<E> a4;
}

我正在考虑使用特征类。但我希望有更简单的方法来实现这一点。 谢谢

【问题讨论】:

  • D 和 E 有什么特别之处吗?即成员函数,特征
  • 是的。他们有一个成员函数,比如说“void bar()”,而其他人没有。
  • 类型是否相关;他们有共同的基础吗?
  • @Jason 不,他们没有。
  • 怎么会有A&lt;B&gt; a1;A 类未模板化。

标签: c++ templates c++11


【解决方案1】:

使用 Walter Brown 的 (C++1z) void_t

#include <iostream>
#include <type_traits>

template <typename...>
using void_t = void;

template <typename T, typename = void>
struct has_bar 
  : std::false_type { };

template <typename T>
struct has_bar<T, void_t<decltype( std::declval<T&>().bar() ) > >
  : std::true_type { };

class A {
  public:
    void foo() { };
};

class B {
  public:
    void bar() { };
};

class C {
  public:
    void bar() { };
};

template <typename T> 
typename std::enable_if<!has_bar<T>::value, void>::type
fun(T t) {
  std::cout << "fun" << std::endl;
}

template <typename T>
typename std::enable_if<has_bar<T>::value, void>::type
fun(T t) {
  std::cout << "special fun" << std::endl;
}

代码...

int main(const int argc, const char* argv[argc]) {

  A a;
  B b;
  C c;

  fun(a);
  fun(b);
  fun(c);

  return 0;
}

打印出来

fun
special fun
special fun

注意,这不会检查任何类型语义,因此最好将bar() 声明为接口并使用std::is_base_of

【讨论】:

    【解决方案2】:

    你应该看看 SFINAE 在编译时启用和禁用功能

    如果 D 和 E 是特殊的,假设他们有成员 void bar() 而不是其他成员,您实际上可以实现自己的类型特征:

    template<typename T>
    struct has_bar {
    private:
        template<typename C> static std::true_type test(decltype(&C::bar)*);
        template<typename C> static std::false_type test(...);
    
    public:
        constexpr static bool value = decltype(test<T>(nullptr))::value;
    };
    
                         /* false */          /* true */
    cout << boolalpha << has_bar<A> << " " << has_bar<E> << endl;
    

    现在有了这种类型特征,您可以使用std::enable_if 作为编译时开关:

                                       /* standard if no bar */
    template<typename T, typename = enable_if_t< !has_bar<T> >>
    void foo()
    {
        //standard implementation
    }
    
                                       /* special if bar */
    template<<typename T, typename = enable_if_t< has_bar<T> >>
    void foo()
    {
        //special implementation
    }
    

    【讨论】:

    • 如果C::bar 过载则失败。请参阅@Jason 的答案以获取仅检查 bar 是否存在不存在参数的替代方法。
    【解决方案3】:

    AFAIK 如果不定义一些 SFINAE 机器,您将无法做到这一点。现在我能想到的不包括type_traits 标头的最小值如下:

    如下定义“自制”enable_ifis_same 类型特征。

    namespace mine {
      template<bool, typename T = void> struct enable_if {};
      template<typename T> struct enable_if<true, T> { typedef T type; };
      template<typename T, typename U> struct is_same { static bool const value = false; };
      template<typename T> struct is_same<T, T> { static bool const value = true; };
    };
    

    class A的成员函数foo()中应用SFINAE如下:

    class A {
      template<typename T>
      struct pred {
        static bool const value = mine::is_same<T, B>::value || 
        mine::is_same<T, C>::value || mine::is_same<T, D>::value || mine::is_same<T, E>::value;   
      };
    public:
      template<typename T> 
      typename mine::enable_if< pred<T>::value, void>::type
      foo() { std::cout << "special implementation"  << std::endl; }
    
      template<typename T>
      typename mine::enable_if<!pred<T>::value, void>::type
      foo() {std::cout << "standard implementation" << std::endl; }
    };
    

    LIVE DEMO

    P.S 的好处是上述解决方案也适用于 C++11 之前的编译器。

    【讨论】:

      猜你喜欢
      • 2013-07-11
      • 2019-08-20
      • 2017-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      相关资源
      最近更新 更多