g ++编译器错误:无法推断模板参数'_Funct'

Spa*_*ter 9 c++ foreach templates

我正在尝试使用ANSI C++ for_each语句迭代并打印标准向量的元素.如果我有for_each调用非重载函数,它会工作,但如果我调用一个重载函数,则会产生编译器错误.

这是一个最小的测试程序,用于显示编译器错误发生的位置:

#include <algorithm>
#include <iostream>
#include <vector>

struct S {
    char c;
    int i;
};
std::vector<S> v;

void print_struct(int idx);
void print_struct(const struct S& s);

// f: a non-overloaded version of the preceding function.
void f(const struct S& s);

int main()
{
    v.push_back((struct S){'a', 1});
    v.push_back((struct S){'b', 2});
    v.push_back((struct S){'c', 3});

    for (unsigned int i = 0; i < v.size(); ++i)
        print_struct(i);

    /* ERROR! */
    std::for_each(v.begin(), v.end(), print_struct);

    /* WORKAROUND: */
    std::for_each(v.begin(), v.end(), f);

    return 0;
}

// print_struct: Print a struct by its index in vector v.
void print_struct(int idx)
{
    std::cout << v[idx].c << ',' << v[idx].i << '\n';
}

// print_struct: Print a struct by reference.
void print_struct(const struct S& s)
{
    std::cout << s.c << ',' << s.i << '\n';
}

// f: a non-overloaded version of the preceding function.
void f(const struct S& s)
{
    std::cout << s.c << ',' << s.i << '\n';
}
Run Code Online (Sandbox Code Playgroud)

我使用以下命令在openSUSE 12.2中编译了这个:

g++-4.7 -ansi -Wall for_each.cpp -o for_each
Run Code Online (Sandbox Code Playgroud)

完整的错误消息是:

for_each.cpp: In function ‘int main()’:
for_each.cpp:31:48: error: no matching function for call to ‘for_each(std::vector<S>::iterator, std::vector<S>::iterator, <unresolved overloaded function type>)’
for_each.cpp:31:48: note: candidate is:
In file included from /usr/include/c++/4.7/algorithm:63:0,
                 from for_each.cpp:5:
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct)
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note:   template argument deduction/substitution failed:
for_each.cpp:31:48: note:   couldn't deduce template parameter ‘_Funct’
Run Code Online (Sandbox Code Playgroud)

我没有在Stack Overflow或Web上看到任何针对此特定错误的搜索结果.任何帮助,将不胜感激.

seh*_*ehe 7

名称是指过载集.您需要指定所需的过载:

std::for_each(v.begin(), v.end(), (void (&)(S const&)) print_struct);
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用多态可调用函数对象作为帮助器:

struct PrintStruct
{
    template <typename T> void operator()(T const& v) const 
        { return print_struct(v); }
};

int main()
{
    PrintStruct helper;

    std::vector<S> sv;
    std::vector<int> iv;

    // helper works for both:
    std::for_each(sv.begin(), sv.end(), helper);
    std::for_each(iv.begin(), iv.end(), helper);
Run Code Online (Sandbox Code Playgroud)


Xeo*_*Xeo 5

std::for_each 声明看起来像这样:

template<class InputIter, class Func>
void for_each(InputIter first, InputIter last, Func func);
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,它需要什么你给它作为第三个参数。没有任何限制,它必须一定是某个签名的可调用类型,也可以一定是可调用类型。

在处理重载函数时,除非您为它们提供一些上下文来选择正确的函数,否则它们本质上是模棱两可的。在对重载函数的调用中,此上下文是您传递的参数。但是,当您需要一个指针时,就不能将参数用作上下文,并且该for_each参数也不能算作上下文,因为它需要任何东西。

作为一个函数参数可以作为选择正确的重载的有效上下文的示例,请参见:

// our overloads
void f(int){}
void f(double){}

typedef void (*funcptr_type)(int);
void g(funcptr_type){}

// ...
g(&f); // will select 'void f(int)' overload, since that's 
       // the only valid one given 'g's parameter
Run Code Online (Sandbox Code Playgroud)

如您所见,您在此处提供了一个清晰的上下文,可帮助编译器选择正确的重载而不会造成歧义。std::for_each的参数没有给出这样的上下文,因为它们可以接受任何内容。

有两种解决方案:

  • 通过以下方式手动提供上下文
    • 强制转换为正确的函数指针类型,或者
    • 使用正确类型的中间变量并将其传递
  • 使用一个非重载的函数,该函数会分派给一个重载的函数(就像您对进行的操作f

请注意,在C ++ 11中,您还可以将lambda用作第二个选项:

std::for_each(v.begin(), v.end(), [](const S& s){ print_struct(s); });
Run Code Online (Sandbox Code Playgroud)

有关代码的一些注意事项:

  • (struct S){'a', 1} 是复合文字而不是标准C ++
  • 你不需要struct S在C ++中,只S就足够了