使用ENABLE_IF和SFINAE时,功能参数类型扣除(std容器,例如向量)失败



我似乎无法弄清楚我的出错。请参阅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";
}

在这种情况下,类型 - 否定词适合此片段:

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

好的。因此,现在我想键入-deDuce我的参数并启用_.如果容器类揭示了Typedef Iterator。我使用Herb 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&amp;("的匹配函数 dosomethingsmartly(v(;// - 失败! ^PROG.CPP:26:6:注意:候选人:template c,t类,A类> void dosomethingsmartly(typeName std :: enable_if> :: value> :: value> ::类型&amp;( void dosomethingsmartly( ^~~~~~~~~~~~~~~~~prog.cpp:26:6:注意:模板参数扣除/替换失败:PROG.CPP:44:22:注意:无法推断模板参数'模板类C' dosomethingsmartly(v(;// - 失败!

我在做什么错?

在您的尝试中, CTA在非可分配上下文中(在 traits<T>::type中,在非可推迟上下文中的 T中(,您可以在返回类型上使用 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)
{
   // ...
}

@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<C<T,A>>::value中的C<T,A>在不可用的上下文中。

此答案更详细地解释它。

以下更改将解决此问题:

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,因此您永远不必传递其他参数。

我弄清楚了。我真正想要的是(我实际上不在乎迭代,这是揭露语法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";
}

...但是我仍然想知道为什么原始尝试中的类型扣除失败!