C++ 变量和函数重载解析

C++ 变量和函数重载解析,c++,boost,C++,Boost,以下代码未编译: #包括 A类{}; B类{}; C类{}; D类{}; 使用v1=boost::variant; 使用v2=boost::variant; int f(v1常数&){ 返回0; } int f(v2常数&){ 返回1; } int main(){ 返回f(A{}); } gcc和clang均投诉: test1.cpp: In function ‘int main()’: test1.cpp:18:17: error: call of overloaded ‘f(A)’ is

以下代码未编译:

#包括
A类{};
B类{};
C类{};
D类{};
使用v1=boost::variant;
使用v2=boost::variant;
int f(v1常数&){
返回0;
}
int f(v2常数&){
返回1;
}
int main(){
返回f(A{});
}
gcc和clang均投诉:

test1.cpp: In function ‘int main()’:
test1.cpp:18:17: error: call of overloaded ‘f(A)’ is ambiguous
     return f(A{});
                 ^
test1.cpp:18:17: note: candidates are:
test1.cpp:11:5: note: int f(const v1&)
 int f(v1 const&) {
     ^
test1.cpp:14:5: note: int f(const v2&)
 int f(v2 const&) {

鉴于无法从
a
实例构造
v2
对象,为什么编译器在重载解析过程中对这两个函数赋予相同的优先级?

这是一种实用的方法,不需要使用正确的SFINAE显式转换来修复转换(我认为在Boost Variant库之外无法优雅地完成),可能是这样的:

查看它

#include <boost/variant.hpp>

class A {};
class B {};
class C {};
class D {};

using v1 = boost::variant<A, B>;
using v2 = boost::variant<C, D>;

namespace detail {
    struct F : boost::static_visitor<int> {
        template <typename... T>
        int operator()(boost::variant<T...> const& v) const {
            return boost::apply_visitor(*this, v);
        }

        int operator()(A) const { return 0; }
        int operator()(B) const { return 0; }
        int operator()(C) const { return 1; }
        int operator()(D) const { return 1; }
    } _f;
}

template <typename T>
int f(T const& t) {
    return detail::F()(t);
}

int main() {
    std::cout <<  f(A{})   << "\n";
    std::cout <<  f(B{})   << "\n";
    std::cout <<  f(C{})   << "\n";
    std::cout <<  f(D{})   << "\n";
    std::cout <<  f(v1{})  << "\n";
    std::cout <<  f(v2{})  << "\n";
}

假设
f(T)
总是为相同的
T
返回相同的值,即使它是多个变量的成员

问题在于构造函数

template<typename T>
variant(const T&)
我认为只有当 参数实际上可以转换为参数,您可能希望
将此作为错误提出。

variant
具有隐式模板转换构造函数。如果这些构造函数没有使用
enable\u(如果
启用)进行充分保护,则可能会导致此问题。请注意,这是同一问题
std::function
has@Yakk有意思。我从来没有遇到过这个问题。有博士吗?@pmr我不知道:但会的在
要求的
之后要干净得多,我很想等待。
template<typename T>
variant(const T&)
struct C {};

struct A {
  A(const C&) {}

  template<typename T>
  A(const T&) {}
};
struct B {
  template<typename T>
  B(const T&) {}
};

int f(const A&) {
    return 0;
}
int f(const B&) {
    return 1;
}
int main() {
  return f(C{});
}