在转换运算符不明确时选择它们

gez*_*eza 3 c++

我有两种类型:

struct A { };
struct B { };
Run Code Online (Sandbox Code Playgroud)

我有功能AB:

void fnA(A); // there are a lot of these functions
void fnB(B);
Run Code Online (Sandbox Code Playgroud)

我有一个类型,可转换为AB:

struct Foo {
    operator A();
    operator B();
};
Run Code Online (Sandbox Code Playgroud)

所以,我可以打电话fnAfnB:

fnA(Foo()); // fine
fnB(Foo());
Run Code Online (Sandbox Code Playgroud)

现在,我有重载功能:

void fn(A);
void fn(B);
Run Code Online (Sandbox Code Playgroud)

我不能打电话给他们Foo,因为它含糊不清:

fn(Foo()); // ambiguous, which fn is called
Run Code Online (Sandbox Code Playgroud)

我希望fn(A)在这种情况下被召唤.

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

inline void fn(Foo foo) {
    fn(A(foo));
}
Run Code Online (Sandbox Code Playgroud)

但我不喜欢这种方式,因为我有很多fn功能,而且我不想大大增加功能的数量(我有fn类似的功能散布在各处,这种改变会增加接口大小,对我来说不好,因为我的界面已经很大了).

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

struct Foo: A {
    operator B();
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,编译器会选择打电话fn(A)fn(Foo()),这一点也不含糊了.但是我不满意这个解决方案,因为Foo它不是真的A,它是对继承的误用(另一方面,它是一个比前一个更好的解决方案,因为它解决了本地问题,我没有添加很多不需要的fn功能).

有没有其他方法可以解决这个问题?

注:我想有一个解决方案,不涉及显式转换,我想能写fnA(Foo()),fnB(Foo())fn(Foo()).

use*_*670 6

一个花哨的模板包装器怎么样:

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);
Run Code Online (Sandbox Code Playgroud)

在线编译器