通过通用引用传递静态constexpr变量



在下文中,static constexpr成员L在类A中初始化,然后通过值或(通用)引用传递。后者在Clang中失败,但在GCC中失败,成员/非成员功能的行为略有不同。更详细地说:

#include <iostream>
using namespace std;
struct A
{
static constexpr size_t L = 4;
template <typename T>
void member_ref(T&& x) { cout << std::forward<T>(x) << endl; }
template <typename T>
void member_val(T x) { cout << x << endl; }
};
template <typename T>
void ref(T&& x) { cout << std::forward<T>(x) << endl; }
template <typename T>
void val(T x) { cout << x << endl; }
int main ()
{
A().member_ref(A::L);  // Clang: linker error: undefined reference to `A::L'
A().member_val(A::L);  // fine (prints 4)
ref(A::L);             // Clang: compiles/links fine, no output
val(A::L);             // fine (prints 4)
}

在将问题与更大的程序隔离开来进行了一些实验之后,我意识到我意外地使用了constexpr变量的地址,尽管我只对值感兴趣。

我想传递(通用)引用,这样代码是通用的,可以在不复制的情况下使用大型结构。我以为你可以通过任何具有普遍参考的东西,但这里的情况似乎并非如此。我不能为L使用单独的(类外)定义,因为这是仅头库的一部分。

因此,一种变通方法可以是在调用时生成一个值,例如size_t(A::L)或类似A::get_L()的东西,而不仅仅是A::L,其中(在类A中)

static constexpr size_t get_L() { return L; }

但这两种解决方案看起来都有点笨拙。在我的实际代码中,调用是在类中进行的,看起来像call(0, L, ...),看起来很无辜(0, L看起来像值)。我希望通话尽可能简单。

我认为这个问题及其后续行动在很大程度上解释了正在发生的事情。那么,有人能建议用什么最干净的方法来处理这个问题吗?

您需要在源文件中的类之外定义A::L

constexpr size_t A::L;

使用Clang 的实时示例

对于只包含头的代码,如果您的类A还不是模板,则可以定义一个具有void默认值的类模板A_<T>,并根据为A编写typedef

template<class = void>
struct A_
{
static constexpr size_t L = 4;
template <typename T>
void member_ref(T&& x) { cout << std::forward<T>(x) << endl; }
template <typename T>
void member_val(T x) { cout << x << endl; }
};
template<class T>
constexpr size_t A_<T>::L;
using A = A_<>;

实例

注意:该业务可能涉及相当数量的锅炉板。值得注意的是,一个人可以写

template
<
class MyConcept1, 
class MyConcept2, 
class YetAnotherConcept
// more long and well-documented template parameter names
>
struct A
{
// many static constexpr variabels
};
template<class P1, class P2, class P3 /* many more short parameter names */>
constexpr SomeType A<P1, P2, P3, /* many more */>::some_var;
// many more one-liners.

模板参数只有正式名称,它们不必在任何地方都相同(不过,只需将它们按的正确顺序放在任何地方!)。

相关内容

  • 没有找到相关文章

最新更新