【问题标题】:c++03: Mutually exclusive methods thanks to enable_ifc++03: 互斥方法感谢 enable_if
【发布时间】:2017-06-19 07:21:48
【问题描述】:

在一个类中,我有两种不同的方法,它们应该是互斥的,具体取决于调用者模板参数。

class Foo
{
    // For collections
    template<class T>
    typename boost::enable_if<boost::is_same<typename std::vector<typename T::value_type>, T>::value, const T&>::type
    doSomething()
    { }


    // For single types
    template<class T>
    typename boost::enable_if<!boost::is_same<typename std::vector<typename T::value_type>, T>::value, const T&>::type
    doSomething()
    { }
}

这不会编译。

错误:'template struct boost::enable_if' 模板参数列表中参数 1 的类型/值不匹配 错误:需要一个类型,得到'! boost::is_same::value'

【问题讨论】:

  • 也许你想要boost::enable_if_c?参见例如the Boost enable_if reference.
  • 为什么不能使用disable_if
  • 奇怪,为什么doSomething()之前指定了const T&amp;,返回类型应该已经被typename boost::enable_if...指定了?
  • 我认为您这里有语法错误?您已经指定了两次返回类型。
  • 是的,正确的。我不需要返回类型两次,复制粘贴错误,我的坏

标签: c++ boost sfinae c++03 enable-if


【解决方案1】:

怎么样:

template <typename T> struct is_std_vector : std::false_type {};
template <typename T, typename A>
struct is_std_vector<std::vector<T, A>> : std::true_type {};

然后

class Foo
{
    // For collections
    template<class T>
    typename std::enable_if<is_std_vector<T>::value, const T&>::type
    doSomething();

    // For single types
    template<class T>
    typename std::enable_if<!is_std_vector<T>::value, const T&>::type
    doSomething();
};

【讨论】:

  • 这有点工作。但是为什么我不能使用自己的语法而不需要定义 is_std_vector 结构呢?
  • T::value_type 不是为所有类型定义的,所以你 SFINAE 也在上面,它对于大多数非容器类型是不正确的。
【解决方案2】:

与 std 的版本不同,boost::enable_if 接受一个类型(布尔值下的某种包装),所以你应该写类似

class Foo
{
    // For collections
    template<class T>
    typename boost::enable_if<
        typename boost::is_same<typename std::vector<typename T::value_type>, T>,
    const T&>::type doSomething()
    { }


    // For single types
    template<class T>
    typename boost::enable_if_с<
        !boost::is_same<typename std::vector<typename T::value_type>, T>::value,
    const T&>::type doSomething()
    { }
}

请注意,我在boost::is_same 之前使用过typename,并且在第一个规范中没有使用过::value。相反,我不得不在第二个重载中使用enable_if_с,因为! 运算符不适用于某个类型。

【讨论】:

    【解决方案3】:

    标签调度怎么样?

    #include <vector>
    #include <iostream>
    
    template <typename, typename>
    struct isSame
     { typedef int type; };
    
    template <typename T>
    struct isSame<T, T>
     { typedef long type; };
    
    struct foo
     {
       template <typename T>
       T const & doSomething (T const & t, int)
        { std::cout << "int version" << std::endl; return t; }
    
       template <typename T>
       T const & doSomething (T const & t, long)
        { std::cout << "long version" << std::endl; return t; }
    
       template <typename T>
       T const & doSomething (T const & t)
        { return doSomething(t, typename isSame<
            typename std::vector<typename T::value_type>, T>::type()); }
     };
    
    int main ()
     {
       foo f;
       std::vector<int> v;
       f.doSomething(v);   // print "long version"
     }
    

    【讨论】:

      【解决方案4】:

      如果你想要的是根据你是否得到一个向量来重载函数

      #include <type_traits>
      #include <iostream>
      #include <vector>
      
      using std::cout;
      using std::endl;
      
      class Foo {
      public:
          // For collections
          template <class T>
          const vector<T>& do_something(const std::vector<T>& input) {
              cout << __PRETTY_FUNCTION__ << endl;
              return input;
          }
      
      
          // For single types
          template <class T>
          const T& do_something(const T& input) {
              cout << __PRETTY_FUNCTION__ << endl;
              return input;
          }
      };
      
      int main() {
          auto foo = Foo{};
          auto v = std::vector<int>{};
          auto i = int{};
          foo.do_something(v);
          foo.do_something(i);
      }
      

      如果您想更通用并检查任何实例化类型

      #include <type_traits>
      #include <iostream>
      #include <vector>
      
      using std::cout;
      using std::endl;
      
      namespace {
      
          template <typename T, template <typename...> class TT>
          struct IsInstantiationOf
                  : public std::integral_constant<bool, false> {};
          template <template <typename...> class TT, typename... Args>
          struct IsInstantiationOf<TT<Args...>, TT>
                  : public std::integral_constant<bool, true> {};
      } // namespace anonymous
      
      class Foo {
      public:
          // For collections
          template <typename VectorType, typename std::enable_if_t<IsInstantiationOf<
                  std::decay_t<VectorType>, std::vector>::value>* = nullptr>
          void do_something(VectorType&&) {
              cout << "Vector overload" << endl;
          }
      
          // For single types
          template <class T, typename std::enable_if_t<!IsInstantiationOf<
                  std::decay_t<T>, std::vector>::value>* = nullptr>
          void do_something(T&&) {
              cout << "Non vector overload" << endl;
          }
      };
      
      int main() {
          auto foo = Foo{};
          auto v = std::vector<int>{};
          auto i = int{};
          foo.do_something(v);
          foo.do_something(i);
      }
      

      另外请注意,由于这些原因https://stackoverflow.com/a/14623831/5501675,您应该尽可能避免将std::enable_if 放在函数签名中

      【讨论】:

      • 函数的返回类型是模板化类型T,用简单的函数重载无法解决,需要SFINAE
      • @codeJack 再次编辑以使用 SFINAE,如果这是你想要的
      • 没有 c++03 并且您更改了函数的签名以使模板参数带有签名。这可能是一种方法,但它没有考虑到所有要求
      • @codeJack 很容易用boost::enable_if_c 替换我的std::enable_if 概念是一样的
      猜你喜欢
      • 1970-01-01
      • 2012-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 1970-01-01
      相关资源
      最近更新 更多