首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用enable_if和SFINAE时,函数参数类型推导(std容器,例如向量)失败

使用enable_if和SFINAE时,函数参数类型推导(std容器,例如向量)失败
EN

Stack Overflow用户
提问于 2017-04-21 15:12:04
回答 3查看 232关注 0票数 0

我似乎找不出哪里出错了。请参阅https://ideone.com/WKsZSN

我正在尝试创建一个仅当它的参数是某种模板类时才存在的函数,该模板类为迭代器提供了一个类型定义。

在非条件情况下,该函数将如下所示:

代码语言:javascript
复制
template<template <class, class> class C, class T, class A>
void DoSomething(C<T,A>& val)
{
    T* pT;
    cout << "did something!\n";
}

在这种情况下,type-deduction可以很好地用于此代码片段:

代码语言:javascript
复制
vector<int> v{1,2,3,4,5};
DoSomething(v);

好的。所以现在我想输入-deduce我的参数,并且enable_if容器类公开了typedef迭代器。使用herb sutter gotw sfinae模式,我创建了:

代码语言:javascript
复制
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);
};

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

代码语言:javascript
复制
vector<int> v{1,2,3,4,5};
DoSomething(v);
cout << "vector<int> supports_iteration? " << 
    boolalpha << supports_iteration<decltype(v)>::value << "!" << endl;

工作正常,输出:

代码语言:javascript
复制
did something!
vector<int> supports_iteration? true!

好了,现在我想使用enable_if升级DoSomething(),如下所示:

代码语言:javascript
复制
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";
}

但这不管用。我得到了

向量:在函数‘int main()’中: prog.cpp:44:22:错误:没有与调用‘DoSomethingSmartly(std::prog.cpp&)’匹配的函数DoSomethingSmartly(v);// -失败!!^ prog.cpp:26:6:注意:候选:模板类C,类T,类A>空类型(DoSomethingSmartly std::enable_if >::value>::type&)空DoSomethingSmartly( ^~ prog.cpp:26:6:注意:模板参数推导/替换失败: prog.cpp:44:22:注意:无法推导模板参数‘模板类C’DoSomethingSmartly(v);// -失败!!

我做错了什么?

EN

回答 3

Stack Overflow用户

发布于 2017-04-21 15:38:31

在您尝试中,CTA处于不可推断上下文中(在traits<T>::type中,T In处于不可推断上下文中),您可以在返回类型上使用enable_if

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2017-04-21 16:00:11

@Jarod42在他的评论中给出了正确的答案,但我将用外行的术语补充一下:

当考虑到...

代码语言:javascript
复制
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>处于不可推断的上下文中。

This answer对此进行了更详细的解释。

以下更改将解决此问题:

代码语言:javascript
复制
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,这样您就永远不需要传入额外的参数。

票数 1
EN

Stack Overflow用户

发布于 2017-04-21 15:27:12

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

代码语言:javascript
复制
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";
}

...but我还是想知道为什么类型推导在最初的尝试中失败了!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43536177

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档