通过通用引用传递一个静态constexpr变量? [英] passing a static constexpr variable by universal reference?
问题描述
在下面, static constexpr
member 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
使用单独的(out-of-class)定义,因为这是一个只有头文件的库的一部分。
所以一个解决方法是在调用时生成一个值,例如 size_t(A :: L)
或类似 A :: get_L()
而不是 A :: L
,其中(在 A
static constexpr size_t get_L(){return L; }
但两个解决方案看起来有点笨拙。在我的实际代码中,调用是在类中,看起来像调用(0,L,...)
这看起来很无辜( L
看上去像值)。我想尽可能简化通话。
你需要定义 A :: L
在源文件中类的外部
constexpr size_t A :: L;
活动示例 使用Clang
对于纯头文件代码,如果您的类 A
不是模板,您可以使用 void 定义类模板
A_< T& code>默认值,并为
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;
使用A = A_<> ;;
模板
<
类MyConcept1,
类MyConcept2,
类YetAnotherConcept
//更长的和详细的模板参数名称
>
struct A
{
//许多静态constexpr variabels
};
模板<类P1,类P2,类P3 / *更多的短参数名称* />
constexpr SomeType A< P1,P2,P3,/ * many more * /> :: some_var;
//更多的单行。
模板参数只是有正式名称,它们不必在任何地方都一样在正确的顺序无处不在,尽管!)。
In the following, static constexpr
member L
is initialized in-class A
and then passed by value or by (universal) reference. The latter fails in Clang but not in GCC, and behaviour is slightly different for member/non-member functions. In more detail:
#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)
}
After some experimentation in isolating the problem from a larger program, I realized that I am accidentally using the address of a constexpr
variable, although I am only interested in the value.
I want to pass by (universal) reference so that the code is generic and works with large structures without copying. I thought that you could pass anything with a universal reference but it appears this is not the case here. I cannot use a separate (out-of-class) definition for L
because this is part of a header-only library.
So one workaround can be to generate a value upon call, i.e. say size_t(A::L)
or something like A::get_L()
instead of just A::L
, where (within class A
)
static constexpr size_t get_L() { return L; }
but both solutions look a bit clumsy. In my actual code the call is made within the class and looks like call(0, L, ...)
which appears quite innocent (0, L
look like values). I'd like to keep the call as simple as possible.
I think this question and its follow-up pretty much explain what is happening. So could anyone suggest what would be the cleanest way to deal with this?
You need to define A::L
outside its class in a source file
constexpr size_t A::L;
Live example using Clang
For header-only code, and if your class A
is not already a template, you can define a class template A_<T>
with a void
default value, and write a typedef for A
in terms of that
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_<>;
NOTE: this business can involve a fair amount of boiler-plate. It is good to note that one can write
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.
Template parameters just have formal names, they don't have to be the same everywhere (just put them in the right order everywhere, though!).
这篇关于通过通用引用传递一个静态constexpr变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!