使用带有右值引用和const类成员数据的参数包扩展会导致Clang 5和6以及GCC 4.8.5和5.3出现链接错误。我第一次遇到与std::make_shared
具有相同签名的函数的问题,但已将其简化为以下测试用例,显示了我希望工作的6种不同方式。
#include <utility>
constexpr int global_value = 3;
struct Foo {
static constexpr int value = 3;
};
struct Bar {
static const int value = 3;
};
using Baz = std::integral_constant<int, 3>;
template<class... Args>
int* make(Args&&... args)
{
return new int(std::forward<Args>(args)...);
}
template<class... Args>
int* make_nofwd(Args&&... args)
{
return new int(args...);
}
template<class... Args>
int* make_norvalue(Args... args)
{
return new int(args...);
}
int main(int, char** )
{
#if ATTEMPT == 0
int* v = make(Foo::value); // FAIL
#elif ATTEMPT == 1
int* v = make_nofwd(Foo::value); // FAIL
#elif ATTEMPT == 2
int* v = make_norvalue(Foo::value); // OK
#elif ATTEMPT == 3
int* v = make(global_value); // OK
#elif ATTEMPT == 4
int* v = make(Bar::value); // OK
#elif ATTEMPT == 5
int* v = make(Baz::value); // OK
#endif
return (*v == 3 ? 0 : 1);
}
运行每次尝试都表明,当作为rvalues传递时,结构的常量和constexpr数据不会被插入。
$ for i in {0..4}; do echo "=== Attempt $i ==="; g++ derp.cc -Wall -Wextra -std=c++11 -D ATTEMPT=$i -o derp.exe && ./derp.exe && echo "SUCCESS" ; done
=== Attempt 0 ===
/tmp/ccC5TyiZ.o: In function `main':
derp.cc:(.text+0x10): undefined reference to `Foo::value'
collect2: error: ld returned 1 exit status
=== Attempt 1 ===
/tmp/ccCwlV85.o: In function `main':
derp.cc:(.text+0x10): undefined reference to `Foo::value'
collect2: error: ld returned 1 exit status
=== Attempt 2 ===
SUCCESS
=== Attempt 3 ===
SUCCESS
=== Attempt 4 ===
/tmp/ccnfzmHk.o: In function `main':
derp.cc:(.text+0x10): undefined reference to `Bar::value'
collect2: error: ld returned 1 exit status
=== Attempt 5 ===
SUCCESS
并且,我刚刚发现任何优化运行都会神奇地修复它:
for i in {0..4}; do echo "=== Attempt $i ==="; $CXX derp.cc -Wall -Wextra -std=c++11 -D ATTEMPT=$i -O2 -o derp.exe && ./derp.exe && echo "SUCCESS" ; done;
=== Attempt 0 ===
SUCCESS
=== Attempt 1 ===
SUCCESS
=== Attempt 2 ===
SUCCESS
=== Attempt 3 ===
SUCCESS
=== Attempt 4 ===
SUCCESS
=== Attempt 5 ===
SUCCESS
我在某种程度上使用未指明的行为吗?为什么Args&&
没有通过值传递int
?