我有两种类型:
struct A { };
struct B { };
我有采用A
或B
的函数:
void fnA(A); // there are a lot of these functions
void fnB(B);
我有一个类型,可以转换为A
和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(A)
调用fn(Foo())
,这不再是模棱两可了。但是我对这种解决方案不满意,因为Foo
并不是真正的A
,这是对继承的滥用(另一方面,它比以前的解决方案更好,因为它可以在本地解决问题,我不必添加很多不需要的fn
函数)。
还有其他解决方法吗?
注意:我想有一个不涉及显式转换的解决方案,我想能够编写fnA(Foo())
,fnB(Foo())
和fn(Foo())
。
答案 0 :(得分: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);
答案 1 :(得分:4)
我认为您可以通过使每个fn(B)
重载模板来实现所需的行为:
void fn(A);
template<class = void>
void fn(B);
void bar()
{
fn(Foo());
fn(A());
fn(B());
}
这将导致重载分辨率在考虑模板函数之前选择fn(A)
。必要的工作等于将template<class = void>
放在每个函数的每个B
重载之前(并且,如果声明与定义分开,则将所有此类函数转换为模板专用化)。
Demo。
答案 2 :(得分:1)
只需将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()));
}