【问题标题】:function argument type deduction (std container e.g. vector) fails when using enable_if and SFINAE使用 enable_if 和 SFINAE 时,函数参数类型推导(std 容器,例如向量)失败
【发布时间】:2017-09-18 01:41:51
【问题描述】:

我似乎无法弄清楚我哪里出错了。 见https://ideone.com/WKsZSN

我正在尝试创建一个函数,该函数仅在其参数是某种模板化类时才存在,该类为迭代器公开了 typedef。

在非条件情况下,函数看起来像这样:

template<template <class, class> class C, class T, class A>
void DoSomething(C<T,A>& val)
{
    T* pT;
    cout << "did something!\n";
}

在这种情况下,类型推导适用于这个 sn-p:

vector<int> v{1,2,3,4,5};
DoSomething(v);

好的。所以现在我想输入 - 推断我的参数和 enable_if 容器类公开 typedef 迭代器。使用草本 sutter gotw sfinae 模式,我创建了:

template<class T> struct supports_iteration
{ 
private:
    typedef char yes[1];
    typedef char no[2];
    template <class C> static yes& foo(typename C::iterator*);
    template <class C> static no& foo(...);
public:
    static constexpr bool value = sizeof(foo<T>(0)) == sizeof(yes);
};

好的,所以使用它,我现在可以检测迭代器是否暴露:

vector<int> v{1,2,3,4,5};
DoSomething(v);
cout << "vector<int> supports_iteration? " << 
    boolalpha << supports_iteration<decltype(v)>::value << "!" << endl;

工作正常并输出:

did something!
vector<int> supports_iteration? true!

好的,现在我想像这样使用 enable_if 升级 DoSomething():

template<template <class, class> class C, class T, class A>
void DoSomethingSmartly(
    typename std::enable_if<
        supports_iteration<
            C<T,A>
        >::value
    >::type& val)
{
    T* pT;
    cout << "did something smartly!\n";
}

但这不起作用。我明白了

prog.cpp:在函数“int main()”中: prog.cpp:44:22: 错误: 没有匹配函数调用‘DoSomethingSmartly(std::vector&)’ DoSomethingSmartly(v);// - 失败!! ^ prog.cpp:26:6:注意:候选:模板类 C,类 T,类 A> void DoSomethingSmartly(typename std::enable_if >::value>::type&) 无效DoSomethingSmartly( ^~~~~~~~~~~~~~~~~~ prog.cpp:26:6:注意:模板参数扣除/替换失败: prog.cpp:44:22:注意:无法推断模板参数“模板类 C” DoSomethingSmartly(v);// - 失败!!

我做错了什么?

【问题讨论】:

    标签: c++ sfinae enable-if type-deduction template-templates


    【解决方案1】:

    在您的尝试中,CTA 处于不可演绎的上下文中(在traits&lt;T&gt;::typeT 处于不可演绎的上下文中),您可以在返回类型上使用enable_if

    template<template <class, class> class C, class T, class A>
    typename std::enable_if<supports_iteration<C<T,A>>::value>::type
    DoSomethingSmartly(C<T, A>& val)
    {
       // ...
    }
    

    【讨论】:

    • “不可演绎的上下文。”有趣的。我会调查的。谢谢。
    【解决方案2】:

    @Jarod42 在他的评论中给出了正确答案,但我会用外行的话来补充:

    当考虑...

    template<template <class, class> class C, class T, class A>
    void DoSomethingSmartly(
        typename std::enable_if<
          supports_iteration<C<T,A>>::value>::type&);
    

    ...编译器无法从向量参数中推断出 C、T、A 的类型,因为 support_iteration&lt;C&lt;T,A&gt;&gt;::value 中的 C&lt;T,A&gt; 处于不可推断的上下文中。

    This answer 更详细地解释了它。

    以下更改将解决此问题:

    template<template <class, class> class C, class T, class A>
        void DoSomethingSmartly(
            C<T,A>& c, //Now deducible...
            typename std::enable_if<supports_iteration<C<T,A>>::value>::type* = 0)
        {
            T* pT;
            cout << "did something smartly!\n";
        }
    

    现在第一个参数用于推导C、T、A,第二个参数用于根据SFINAE判断函数是否可调用。使用* = 0,这样您就不必传入额外的参数。

    【讨论】:

      【解决方案3】:

      我想通了。我真正想要的是这个(实际上我并不关心迭代,它是暴露句法 T::size() 函数的糟糕代理):

      template<template <class, class> class C, class T, class A, 
          typename = decltype(
              declval<C<T,A>>().size()
              ,void()
          )
      >
      void DoSomethingReallySmartly(C<T,A>& val)
      {
          T* pT;
          cout << "did something really smartly!\n";
      }
      

      ...但是我还是想知道为什么原来尝试的类型推导失败了!!!

      【讨论】:

      • traits&lt;T&gt;::type 中,T 在不可演绎的上下文中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-29
      • 2013-03-10
      • 1970-01-01
      相关资源
      最近更新 更多