没有可行的超载' ='用于重载静态成员函数

时间:2014-11-07 20:59:37

标签: c++ static assignment-operator std-function

我有这个简化的代码,它包含一个带有静态函数的类,它存储在map:

#include <iostream>
#include <functional>
#include <map>

class A {
public:
  static void f(const std::string &s) { std::cout << s; }
}; 

std::map<std::string, std::function<void(std::string const &)>> fs; 

int main() {
  fs["f"] = &A::f;
  fs["f"]("hello");
}

这将打印预期的 hello

如果我使用:

重载f(),则会出现问题
 static void f(const std::string &s, int c) { while(c-->0) { std::cout << s; } }

这会导致错误:

 error: no viable overloaded '='
   fs["f"] = &A::f;
   ~~~~~~~ ^ ~~~~~
 /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2241:7: note: candidate function not viable: no overload of 'f' matching 'const std::function<void (const std::basic_string<char> &)>' for 1st argument
       operator=(const function& __x)
       ^
 /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2259:7: note: candidate function not viable: no overload of 'f' matching 'std::function<void (const std::basic_string<char> &)>' for 1st argument
       operator=(function&& __x)
       ^
 /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2273:7: note: candidate function not viable: no overload of 'f' matching 'nullptr_t' for 1st argument
       operator=(nullptr_t)
       ^
 /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2302:2: note: candidate template ignored: couldn't infer template argument '_Functor'
       operator=(_Functor&& __f)
       ^
 /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2311:2: note: candidate template ignored: couldn't infer template argument '_Functor'
       operator=(reference_wrapper<_Functor> __f) noexcept
       ^

然而,调用这两个函数是有效的:

A::f("hello ");
A::f("echo ", 3);

所以,我的问题是:

  1. 为什么这个代码没有编译,即使运算符=似乎存在并且如果我不重载f()也会起作用?
  2. 如何在不同时给两个函数添加不同名称的情况下使其工作?

1 个答案:

答案 0 :(得分:2)

  

为什么即使运算符=似乎存在,此代码也无法编译   和函数,如果我不重载f()?

因为编译器不知道要选择哪个重载。怎么可能?没有标准可以决定哪一个更适合。每个std::function允许分配任意函数对象,并且不检查任何签名。如果您只想保存此特定签名的函数指针,则应该适当地声明map

  

如何在不同时兼顾两种功能的情况下使其工作   名字?

如前所述,它通过将表达式转换为特定类型的函数指针来工作。

fs["f"] = static_cast<void(*)(std::string const&)>( &A::f );

这样就不会出现歧义;只有一个重载可以转换为此函数到指针类型。
如果这更常出现,那么typedef是可行的。

或者是一个小帮助类模板:

template <typename... Exact>
struct funptr
{
    template <typename R>
    constexpr auto operator()(R(*p)(Exact...)) -> decltype(p)
    { return p; }
};

fs["f"] = funptr<std::string const&>()(&A::f);

Demo