C++ 当转换运算符不明确时,在它们之间进行选择

C++ 当转换运算符不明确时,在它们之间进行选择,c++,C++,我有两种类型: struct A { }; struct B { }; 我的函数取A或B: void fnA(A); // there are a lot of these functions void fnB(B); struct Foo { operator A(); operator B(); }; 我有一个类型,可以转换为a和B: void fnA(A); // there are a lot of these functions void fnB(B); str

我有两种类型:

struct A { };
struct B { };
我的函数取
A
B

void fnA(A); // there are a lot of these functions
void fnB(B);
struct Foo {
    operator A();
    operator B();
};
我有一个类型,可以转换为
a
B

void fnA(A); // there are a lot of these functions
void fnB(B);
struct Foo {
    operator A();
    operator B();
};
所以我可以调用
fnA
fnB

fnA(Foo()); // fine
fnB(Foo());
现在,我有一个重载函数:

void fn(A);
void fn(B);
我不能用
Foo
来称呼他们,因为它不明确:

fn(Foo()); // ambiguous, which fn is called
在这种情况下,我想调用
fn(A)

我可以添加第三个
fn
重载:

inline void fn(Foo foo) {
    fn(A(foo));
}
但我不喜欢这种方式,因为我有很多
fn
函数,我不想大幅增加函数的数量(我有
fn
-类函数分散在各地,这种改变会增加接口大小,这对我来说是不好的,因为我的接口已经很大了)

另一个解决方案(如果没有更好的选择,我会选择)是对
Foo
使用继承:

struct Foo: A {
    operator B();
};
在这种情况下,编译器将选择为
fn(Foo())
调用
fn(A)
,它不再是模棱两可的。但是我对这个解决方案不满意,因为
Foo
并不是一个真正的
A
,它是对继承的滥用(另一方面,它是一个比前一个更好的解决方案,因为它在本地解决了问题,我不必添加很多不需要的
fn
函数)


还有别的办法解决这个问题吗


注意:我希望有一个不涉及显式转换的解决方案,我希望能够将
fnA(Foo())
fnB(Foo())
、和
fn(Foo())

转换为适当的类型:

#include <iostream>
#include <string>

struct A { };
struct B { };

struct Foo {
    operator A() { return A{}; };
    operator B() { return B{}; };
};

void fn(A) { std::cout << "A"; }
void fn(B) { std::cout << "B"; }

int main()
{
  fn(static_cast<A>(Foo()));
}
#包括
#包括
结构A{};
结构B{};
结构Foo{
运算符A(){返回A{};};
运算符B(){返回B{};};
};

void fn(A){std::cout一个奇特的模板包装器怎么样:

void fn_impl(A);
void fn_impl(B);

template<typename x_AB = A, typename x_Foo = Foo>
void fn(x_Foo && foo)
{
    return fn_impl(static_cast<x_AB>(foo));
}

fn(Foo()); // calls fn_impl(A);
fn<B>(Foo()); // calls fn_impl(B);
void fn_impl(A);
无效(B);
模板
无效fn(x_Foo&&Foo)
{
返回fn_impl(静态_cast(foo));
}
fn(Foo());//调用fn_impl(A);
fn(Foo());//调用fn_impl(B);

我认为通过使每个
fn(B)
重载一个模板,您可以实现所需的行为:

void fn(A);

template<class = void>
void fn(B);

void bar()
{
    fn(Foo());
    fn(A());
    fn(B());
}
void fn(A);
模板
无效fn(B);
空条()
{
fn(Foo());
fn(A());
fn(B());
}
这导致重载解析在考虑模板化函数之前选择
fn(A)
。必要的工作相当于将
template
放在每个
B
重载之前(如果声明与定义分离,则将所有此类函数转换为模板专门化)


.

“还有其他方法解决这个问题吗?”正确的方法是不要滥用隐式转换运算符。explicit关键字可能会有帮助。
fn(static_cast(Foo());
只需显式告诉编译器要调用哪个重载运算符,例如:
fn((A)Foo())
或者更好的
fn(static_cast(Foo()))
@Jeka:不幸的是,关键是要进行隐式转换。@ArnavBorborah OP不希望这样做,因为他希望能够为其他方法隐式强制转换。@NathanOliver我已经切换了模板参数,所以现在它可以工作了。foo可能也是一个固定类型的参数。现在看起来不错。它还允许您执行
fn({})
fn({});
现在。有没有一种方法可以概括这一点(这样我就不必为我的
fn
类函数创建模板函数)?我的意思是,代替这个解决方案,我可以很容易地使用我已经在我的答案中加入的内联函数。或者是有什么区别使得这个解决方案更好吗?请注意,如果发生这种情况,您还必须显式地使用
fn(B{})
。这(尽管问题中没有说明)可能会发生,因为
fn(B) 
很可能不是为了好玩而写的。@MaxLanghof这些调用中的一个必须是明确的。很好,让我检查一下!(注意,我的问题不是工作量,而是函数的数量和接口大小。因此,如果你的解决方案可行,那么我完全可以-我的问题措辞不正确,我会编辑它)。