嗨,我希望你喜欢这个问题。我指的是包含文件iscntrl
中的函数cctype
、isprint
等。所有这些函数都接受一个int
并返回一个int
。
下面的代码示例在Wandbox中运行良好,编译器设置为clang。但是在我的混合W64,gcc8.1中,它确实产生了编译错误。我试过C++14和C++17。
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <string>
#include <tuple>
#include <functional>
#include <array>
#include <cctype>
//#include <ctype.h>
namespace abc
{
int two_times( int a )
{
printf( "two_times being called\n" );
return 2*a;
}
int three_times( int a )
{
printf( "three_times being called\n" );
return 3*a;
}
}
int main()
{
typedef std::tuple< std::string, std::function<int(int)> > item_t;
std::array< item_t, 3 > array{
std::make_tuple( "three_times", abc::three_times ),
std::make_tuple( "two_times", abc::two_times ),
std::make_tuple( "iscntrl", std::iscntrl ) };
int i = 2;
for( const item_t& item : array )
{
printf( "operation: %s\n", std::get<0>(item).c_str() );
int val = std::get<1>(item)( i );
printf( "val: %d\n", val );
putchar( '\n' );
}
getchar();
return 0;
}
如您所见,我将循环所需的所有相关内容放入数组中。包括分配给cctype函数的函数对象。
two_times和three_times函数的存在是为了表明我设计的其余部分都很好。如果我只使用这些函数,它就能工作。但在我看来,std::iscntrl
只是另一个以int
作为参数并返回int
的函数。但显然没有,因为它会产生以下编译错误:
error: too many arguments to function 'constexpr std::tuple<typename std::__decay_and_strip<_Elements>::__type ...> std::make_tuple(_Elements&& ...) [with _Elements = {}]'
std::make_tuple( "iscntrl", std::iscntrl ) };
哦,是的,如果用#include <ctype.h>
替换包含文件并删除iscntrl
前面的std::
命名空间标签,那么它也突然起作用了。但这不是很好的做法。但也许它告诉了你什么。
让它变得更简单,两者都不起作用:
std::function<int(int)> f;
f = abc::two_times;
printf( “result: %d\n“, f( 4 ) ); // so far fine
f = std::iscntrl;
然后在最后一行:
error: no match for 'operator=' (operand types are 'std::function<int(int)>' and '<unresolved overloaded function type>')
f = std::iscntrl;
我出什么事了吗?有什么简单的解决方案可以让它与gcc一起编译呢?
发布于 2019-08-10 13:48:33
标准库(自C++20以来)中很少有函数被称为https://en.cppreference.com/w/cpp/language/extending_std。所有其他人只能通过适当的论据才能被调用,而不是被占用他们的地址。
即使在此之前,标准也没有保证没有超载,这几乎有同样的效果。
在你的例子中,
即使您只直接包含第一个标头,所有标准标头也可能包含除C和采用的头之外的任何其他标头,因此它们可能都是可用的。
当您传递到模板参数时,编译器无法消除您所指的重载的歧义。
您应该做的是根据需要传递一个lambda转发。更重要的是,您可以使用它将参数强制到unsigned char
的适当范围,避免未定义的行为。
发布于 2019-08-10 13:45:39
std::iscntrl
在错误中被称为<unresolved overloaded function type>
,因为在C++中,这个函数确实是重载的。来自int iscntrl( int )
头的<cctype>
重载和来自<locale>
的bool iscntrl( charT ch, const locale& loc )
重载。编译器不知道这样传递它时要选择哪个函数。
要解决这个问题,并且仍然使用C++版本,您必须传递一个函数,该函数从内部调用iscntrl
:
std::make_tuple( "iscntrl", [](int c) { return std::iscntrl(c); } );
https://stackoverflow.com/questions/57445856
复制相似问题