我在写一个小库,代码如下:
using foo_t = int;
using bar_t = int;
baz_t create_baz(foo_t foo, bar_t bar = default_bar);
我还想要一个create_baz
函数它只需要一个bar
baz_t create_baz(bar_t bar);
,但这将与默认的第一个版本create_baz冲突-因为foo_t
和bar_t
是相同的。所以,我在想:也许我应该把
struct foo_t { int value; }
struct bar_t { int value; }
(或者只是将它们中的一个包装在结构体中),这样类型就会不同,甚至不兼容,并且我将拥有第二个create_baz
。
现在,显然结构体使用起来不太方便。但是,在做这个决定时,还有其他的利弊需要我考虑吗?
我的问题主要是关于c++的,但我想这在C中也有一定的相关性(忽略第一个函数的第二个参数)。
以下不是您确切问题的答案,但BOOST_STRONG_TYPEDEF
似乎可以很好地创建不兼容的类型:
#include <boost/strong_typedef.hpp>
// Only the header is required. No linking, no runtime dependencies.
BOOST_STRONG_TYPEDEF(int, foo_t);
BOOST_STRONG_TYPEDEF(int, bar_t);
void create_baz(foo_t foo, bar_t bar = static_cast<bar_t>(1)) {}
void create_baz(bar_t bar) {}
int main()
{
// Assigning (or initializing with) literals seems to be
// the only inconvenient thing about strong typedefs.
foo_t a = static_cast<foo_t>(1);
foo_t b = static_cast<foo_t>(2);
a = b; // Operators work well.
std::cout << a+b << std::endl; // Even overloaded ones.
create_baz(a); // No errors, no ambiguity.
return 0;
}
消除函数调用歧义的常见、基本和明显的技术是添加额外的形参并依赖重载。
它是如此常见,甚至标准模板库中的一些类也使用它。
作为一个例子,考虑std::allocator_arg_t
的目的:
[…一个空类类型,用于消除分配器感知对象的构造函数和成员函数的重载歧义[…]
std::function
、std::tuple
、std::promise
、std::packaged_task
使用
您可以很容易地查看这些类的构造函数列表,以了解它是如何使用的。
另一个例子是后置自增/自减操作符。它有一个伪 int
参数,有助于区分函数声明和前缀自增/自减操作符。
即:
T& operator++(T&)
和
T& operator++(T&, int)
这里的调用不需要你提供额外的参数,它实际上只是用来消除函数声明的歧义,所以它是一个人为的例子。
不管怎样,在你的情况下你能做些什么呢?你可以像这样定义一个标签:
struct bar_arg_t {};
并在第二个函数声明中使用它:
baz_t create_baz(bar_arg_t, bar_t bar);
这只不过是一个空类,一个虚拟参数,其目的是帮助您消除调用的歧义。