【问题标题】:Cannot inititialize std::function implicitly无法隐式初始化 std::function
【发布时间】:2013-10-16 10:11:49
【问题描述】:

我编写了这个函子来执行 and 操作(&&):

// unary functor; performs '&&'
template <typename T>
struct AND
{
    function<bool (const T&)> x;
    function<bool (const T&)> y;

    AND(function<bool (const T&)> xx, function<bool (const T&)> yy) 
             : x(xx), y(yy) {}
    bool operator() ( const T &arg ) { return x(arg) && y(arg); }
};

// helper
template <typename T>
AND<T> And(function<bool (const T&)> xx, function<bool (const T&)> yy)
{
    return AND<T>(xx,yy);
}

注意它是构造函数参数类型:function&lt;bool (const T&amp;)&gt;

现在,我正在尝试以各种方式实例化它(在big_odd_exists() 内):

int is_odd(int n) { return n%2; }
int is_big(int n) { return n>5; }


bool big_odd_exists( vector<int>::iterator first, vector<int>::iterator last ) 
{
    function<bool (const int &)> fun1 = is_odd;
    function<bool (const int &)> fun2 = is_big;

    return any_of( first, last, And( fun1, fun2 ) );  // instantiating an And object
}

int main()
{
    std::vector<int> n = {1, 3, 5, 7, 9, 10, 11};

    cout << "exists : " << big_odd_exists( n.begin(), n.end() ) << endl;
}

令我惊讶的是,std::functions 的所有隐式实例都无法编译。

以下是我尝试过的案例(g++-4.8):

这会编译(显式 std::function 对象的实例化):

function<bool (const int &)> fun1 = is_odd;
function<bool (const int &)> fun2 = is_big;

return any_of( first, last, And( fun1, fun2 ) );

编译(隐式临时std::function对象的实例化):

return any_of( first, last, And( is_odd, is_big ) );   // error: no matching function for call to ‘And(int (&)(int), int (&)(int))’

这编译(显式 std::function 对象的实例化):

function<bool (const int &)> fun1 = bind(is_odd,_1);
function<bool (const int &)> fun2 = bind(is_big,_1);

return any_of( first, last, And(fun1, fun2) );

编译(隐式临时std::function对象的实例化):

return any_of( first, last, And(bind(is_odd,_1), bind(is_big,_1)) );  // error: no matching function for call to ‘And(std::_Bind_helper<false, int (&)(int), const std::_Placeholder<1>&>::type, std::_Bind_helper<false, int (&)(int), const std::_Placeholder<1>&>::type)’

据我了解,std::functions 确实 没有 有明确的构造函数。 那么,为什么我不能使用 nicer 来阅读 版本的调用呢?

我有所有的测试用例: http://coliru.stacked-crooked.com/a/ded6cad4cab07541

【问题讨论】:

  • 检查函数is_bigis_odd的返回类型,并与您尝试创建的std::function对象的返回类型进行比较。
  • @JoachimPileborg :他们返回一个int,我正在尝试创建一个function&lt;bool (const int &amp;)&gt;。那么,int 作为参数有什么问题呢?
  • 返回 int 的函数永远不会与返回 bool 的函数相同。
  • @JoachimPileborg:是的,你是对的。不幸的是,这并没有什么区别,因为即使我将is_odd 定义为bool is_odd(const int &amp;),编译器也无法推断出T 是什么类型。

标签: c++ c++11 stl


【解决方案1】:

问题是在这种情况下无法推断出T。我们从编译器的角度来看:

template <typename T>
AND<T> And(function<bool (const T&)> xx, function<bool (const T&)> yy)

// Later, invoked as:
And( is_odd, is_big )

“嗯,调用时没有指定T,我得推导出来。参数是什么?is_odd,它被衰减为类型int (*)(int)。现在,我必须实例化std::function&lt;bool (const T&amp;)&gt;对于所有可能的 T 值,并查看可以从类型 int (*)(int) 构造哪个/如果有的话。嗯,它们有无数个。不会这样做。“

如果您明确指定 T tempalte 参数,它将起作用:

return any_of( first, last, And<int>( is_odd, is_big ) );

Live example


请注意,即使您更改 is_oddis_big 以完全匹配 function 签名(返回 bool 并采用 const int&amp;),这仍然成立。问题出在推论上。

【讨论】:

  • 如果编译器将所有模板都实例化,这甚至没有帮助,因为结果仍然是模棱两可的。通过额外的重载template&lt;typename R, typename A&gt; AND&lt;A&gt; And(R (*xx)(A), R (*yy)(A)),您甚至不需要显式模板参数。真正的问题是过早丢弃参数的类型。
【解决方案2】:

我建议不要滥用std::function 而是使用普通的泛型参数。将std::function 视为特定签名的可调用对象的类型擦除容器(有关详细信息,请参阅https://stackoverflow.com/a/11629125/46642)。

// unary functor; performs '&&'
template <typename X, typename Y>
struct AND
{
    X x;
    Y y;

    template <typename XX, typename YY>
    AND(XX&& xx, YY&& yy) 
             : x(std::forward<XX>(xx)), y(std::forward<YY>(yy)) {}

    template <typename T>
    auto operator() ( const T &arg ) -> decltype(x(arg) && y(arg))
    { return x(arg) && y(arg); }
};

template <typename T>
using Decay = typename std::decay<X>::type;

// helper
template <typename X, typename Y>
AND<Decay<X>, Decay<Y>> And(X&& xx, Y&& yy)
{
    return AND<Decay<X>, Decay<Y>>(std::forward<X>(xx), std::forward<Y>(yy));
}

【讨论】:

  • @GrimFandango 你的评论// won't compile 是……错了吗?从您链接到的页面中可以看出,它可以正常编译和运行。
  • @Martinho:这个模板化的 operator() 正是我所需要的。感谢那!我在 coliru.stacked-crooked.com/a/835af28ac3d18e72 中重新创建了您的解决方案的简化版本。我在 C++0x 中,所以不能使用 &&。相反,我通过价值传递一切。不过,看看您的解决方案,我不明白std::decay 的需求是什么。我在 Josuttis 的书中找不到任何内容。通过查看 cppreference.com,我了解到如果模板参数是一个函数,它会删除 &amp; 并在其中添加 *。这样做的目的是什么?
  • 如果&amp; 类似于foo&amp;,它也会删除它。基本上decay 模拟按值传递语义,我使用它是因为我希望And 始终按值而不是按引用来存储函数对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多