考虑以下代码片段,就像写在头文件中一样:
struct Foo {
// ...
};
template <class... Args>
Foo makeFoo(Args &&... args) {
return {std::forward<Args>(args)...};
}
我可以用一些参数调用makeFoo
,然后返回一个Foo
。太好了。
现在我要做的是用标签替换一些makeFoo
的参数,看起来就像这样(仍在头文件中):
constexpr struct tag_type { using type = ActualType; } tag;
应该在 makeFoo
中检测到这些标签,并在调用 Foo
的构造函数之前替换实际对象。所以调用看起来像:
auto myFoo = makeFoo("hi", ::tagBar, 42, ::tagBaz);
但这里有一个问题:这种声明我的标签的方式非常方便,但是如果我 ODR 使用它们中的任何一个,我需要在其他地方提供一个定义。一点都不方便。
并根据this conveniently specific answer (强调我的):
"the object isn't odr-used" is probably the only questionable condition. Basically, it requires that you don't necessitate the variables runtime existence as a symbol, which in turn implies that
- You don't bind it to a reference (=> you don't forward it!)
- [...]
...我真的很困惑。
如何在不使用 ODR 的情况下从参数中筛选出标签,同时完美转发其他参数?
“标签”被定义为具有
type
typedef 的东西。每个标记声明都由宏
defineTag(name, ActualType)
生成,因此只要它是独立的并且不会改变(太多),就可以改变它调用makeFoo
的语法。完全不涉及 ODR 的替代解决方案就可以了。
C++17 的内联变量听起来像是救赎,但我想避免为那个单一问题将自己锁定在这个项目的前沿编译器中。
最佳答案
如果您可以更改获取type
的方式,则可以通过使用枚举常量来避免更改makeFoo
调用,这些常量计算为不同类型的纯右值:
template <typename> struct tag_helper;
enum { tagBar }; template <> struct tag_helper<decltype(tagBar)> { using type = Bar; };
enum { tagBaz }; template <> struct tag_helper<decltype(tagBaz)> { using type = Baz; };
auto myFoo = makeFoo("hi", ::tagBar, 42, ::tagBaz);
关于c++ - 无 ODR 使用的完美转发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42890559/