假设我有一个编译时constexpr数组和一个可变参数类模板,其中包含一组与数组元素相同类型的非类型参数.
我的目标是使用数组中的值实例化类模板:
struct Container
{
int containee[3];
};
constexpr Container makeContainer();
template <int... Elements> class Foo;
Foo<makeContainer().containee[0],
makeContainer().containee[1],
makeContainer().containee[2]> foo;
Run Code Online (Sandbox Code Playgroud)
上面的代码效果很好.但是,每当我需要实例化Foo模板时,我都不得不手动索引数组.我想编译器自动为我做这件事:
Foo<Magic(makeContainer().containee)> foo;
Run Code Online (Sandbox Code Playgroud)
我在cppreference做了一些RTFM,但这没有帮助.我知道std::forward<>(),但它不能应用于模板参数列表.
c++ templates template-meta-programming variadic-templates constexpr
以下代码在g ++中编译时没有问题:
#include <iostream>
#include <string>
#include <tuple>
template<typename T>
void test(const T& value)
{
std::tuple<int, double> x;
std::cout << std::get<value>(x);
}
int main() {
test(std::integral_constant<std::size_t,1>());
}
Run Code Online (Sandbox Code Playgroud)
我使用了这个命令:
g++ test.cpp -o test -std=c++14 -pedantic -Wall -Wextra
Run Code Online (Sandbox Code Playgroud)
但是当我切换g++到clang++(使用g ++ 5.1.0和clang ++ 3.6.0)时,我收到以下错误:
test.cpp:9:18: error: no matching function for call to 'get'
std::cout << std::get<value>(x);
^~~~~~~~~~~~~~~
test.cpp:13:5: note: in instantiation of function template specialization 'test<std::integral_constant<unsigned long, 1> >' requested here
test(std::integral_constant<std::size_t,1>());
^~~~~~~~~~~~~~~
<skipped>
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.1.0/../../../../include/c++/5.1.0/tuple:867:5: note: candidate template ignored: …Run Code Online (Sandbox Code Playgroud) 考虑以下功能:
template <size_t S1, size_t S2>
auto concatenate(std::array<uint8_t, S1> &data1, std::array<uint8_t, S2> &data2) {
std::array<uint8_t, data1.size() + data2.size()> result;
auto iter = std::copy(data1.begin(), data1.end(), result.begin());
std::copy(data2.begin(), data2.end(), iter);
return result;
}
int main()
{
std::array<uint8_t, 1> data1{ 0x00 };
std::array<uint8_t, 1> data2{ 0xFF };
auto result = concatenate(data1, data2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当使用clang 6.0编译时,使用-std = c ++ 17,此函数无法编译,因为数组上的size成员函数不是constexpr,因为它是一个引用.错误消息是这样的:
错误:非类型模板参数不是常量表达式
当参数不是引用时,代码按预期工作.
我想知道为什么会这样,因为size()实际上返回一个模板参数,它几乎不再是const.参数是否是参考不应该有所作为.
我知道我当然可以使用S1和S2模板参数,该功能仅仅是问题的简短说明.
标准中有什么吗?我很惊讶地发现了编译错误.
以下代码只能在 GCC 上编译(在 godbolt.org 上检查了 10.4 和 13.2),但不能在 Clang 上编译(在我尝试过的所有版本上都失败,例如 godbolt.org 上的 17.0.1):
struct A {
static constexpr int b{1};
};
int main(int argc, char *argv[]) {
A a;
A& aref{a};
constexpr auto bb1{a.b};
constexpr auto bb2{aref.b};
return bb1+bb2;
}
Run Code Online (Sandbox Code Playgroud)
叮当输出:
struct A {
static constexpr int b{1};
};
int main(int argc, char *argv[]) {
A a;
A& aref{a};
constexpr auto bb1{a.b};
constexpr auto bb2{aref.b};
return bb1+bb2;
}
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/nG4j3KefE
为什么?