无需使用 ODR 即可实现完美转发



请考虑以下代码片段,就像写在头文件中一样:

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">可能是唯一有问题的条件。基本上,它要求您不需要变量运行时作为符号存在,这反过来意味着

  • 您不会将其绑定到引用(=>您不转发它!
  • [...]

。我确实在泡菜。

如何在不使用 ODR 的情况下从参数中筛选出标签,同时完美转发其他参数?

  • "标记"被定义为具有type类型定义的东西。

  • 每个标签声明都是由一个宏defineTag(name, ActualType)生成的,所以只要它是自包含的并且不会改变(太多)调用makeFoo的语法,就可以改变它。

  • 完全不关心ODR的替代解决方案很好。

  • C++17 的内联变量听起来像是救赎,但我想避免将自己锁定在这个项目中的前沿编译器中。

如果可以更改获取type的方式,则可以通过使用枚举常量来避免更改makeFoo调用,枚举常量计算为不同类型的 prvalue:

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);

生成标签的constexpr函数怎么样?

constexpr struct tag_type { using type = ActualType; };
constexpr tag_type tag() { return {}; }

用法:

auto myFoo = makeFoo("hi", ::tagBar(), 42, ::tagBaz())

或者,您可以就地从其类型中构造标记,而不是使用函数:

constexpr struct tag { using type = ActualType; };

用法:

auto myFoo = makeFoo("hi", ::tagBar{}, 42, ::tagBaz{})

你可以让你的标签成为变量模板吗?

template <class T>
struct tag_t { using type = T; };
template <class T>
constexpr tag_t<T> tag{};

您将将其用作:

auto myFoo = makeFoo("hi", ::tag<Bar>, 42, ::tag<Baz>);

执行此操作的正常方法不是简单地声明 constexpr 标签定义是静态的吗?

据推测,Foo的构造函数只对类型感兴趣,因此标签类型的多个模型的存在并不重要。

#include <utility>
struct Foo {
template<class...Args>
Foo(Args&&...args)
{}
// ...
};
template <class... Args>
Foo makeFoo(Args &&... args) {
return {std::forward<Args>(args)...};
}
struct Bar {};
struct Baz {};
static constexpr struct tagBar_type { using type = Bar; } tagBar {};
static constexpr struct tagBaz_type { using type = Baz; } tagBaz {};
int main()
{
auto myFoo = makeFoo("hi", ::tagBar, 42, ::tagBaz);
}

相关内容

  • 没有找到相关文章

最新更新