为什么编译器抱怨歧义

Deb*_*h C 1 c++

在下面的代码中,编译器抱怨不明确。为什么?显然我正在传递非 const non & 对象。

\n
#include <stdio.h>\n#include <ranges>\n#include <vector>\n#include <string>\n#include <iostream>\n\nusing namespace std;\ntemplate<class T>\nstring toStr(const T& obj)\n{\n    return obj.toStr();\n}\n\ntemplate<class T>\nstring toStr(T val)\n{\n    return std::to_string(val);\n}\nstruct A\n{\n  string toStr(){return "A";}  \n};\nint main()\n{\n    A a;\n\n    cout << toStr(static_cast<const A&>(a)) << '\\n';\n\n    return 0;\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

我尝试在不同的编译器上编译它。效果是相同的。\n我什至尝试将其转换为所需的 const & 类型。没有。

\n
cout << toStr(static_cast<const A&>(a)) << '\\n';\n
Run Code Online (Sandbox Code Playgroud)\n

编辑:

\n
> main.cpp: In function \xe2\x80\x98int main()\xe2\x80\x99: main.cpp:35:18: error: call of\n> overloaded \xe2\x80\x98toStr(const A&)\xe2\x80\x99 is ambiguous    35 |     cout <<\n> toStr(static_cast<const A&>(a)) << '\\n';\n>       |             ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:17:8: note: candidate: \xe2\x80\x98std::string toStr(const T&) [with T = A; std::string\n> = std::__cxx11::basic_string]\xe2\x80\x99    17 | string toStr(const T& obj)\n>       |        ^~~~~ main.cpp:23:8: note: candidate: \xe2\x80\x98std::string toStr(T) [with T = A; std::string = std::__cxx11::basic_string]\xe2\x80\x99    23\n> | string toStr(T val)\n>       |        ^~~~~\n
Run Code Online (Sandbox Code Playgroud)\n

真正令人沮丧的是错误消息中的这一行:\nerror: call of

\n
\n

重载的 \xe2\x80\x98toStr(const A&)\xe2\x80\x99 是不明确的\n如果恰好有一个具有这样签名的函数,那么 this^^^ 怎么会是不明确的呢?

\n
\n

Ted*_*gmo 5

cout << toStr(a) << '\n';
Run Code Online (Sandbox Code Playgroud)

您将类型的左值传递AtoStr()

现在可以将其转换为const A&匹配的

const T& obj
Run Code Online (Sandbox Code Playgroud)

或将其复制到A匹配的

T val
Run Code Online (Sandbox Code Playgroud)

没有一个比另一个更专业,因此存在歧义。

请注意,A::toStr()应该有const资格在版本中使用string toStr(const T& obj)

然后,您可以添加一些约束来选择正确的重载,例如检查类型是否具有toStr成员函数:

template <class, class = void>
struct has_toStr : std::false_type {};

template <class T>
struct has_toStr<T, std::void_t<decltype(std::declval<T&>().toStr())> >
    : std::true_type {};

template <class T>
inline constexpr bool has_toStr_v = has_toStr<T>::value;

template <class T>
std::string toStr(const T& obj)
    requires has_toStr_v<T>
{
    return obj.toStr();
}

template <class T>
std::string toStr(T val)
    requires(not has_toStr_v<T>)
{
    return std::to_string(val);
}
Run Code Online (Sandbox Code Playgroud)