Reputation: 5462
In the following example I want to transform some constexpr
values into template non-type parameters.
Here I have some constexpr
values a1
and a2
. I can use there (also constexpr
) data-member d
as non-type template parameters for the template B
.
But if I try to take place this sort of transformation in some function transform
this clearly doen't work anymore, since the parameter tuple
isn't considered constexpr
.
#include <cstdint>
#include <tuple>
template<auto N>
struct A {
inline static constexpr auto size = N;
const uint8_t d[N] {};
};
template<auto N, auto... II>
struct B {};
constexpr auto a1 = A<2>{1, 2};
constexpr auto a2 = A<3>{2, 3, 4};
constexpr auto t1 = std::tuple(a1, a2);
constexpr auto b1 = B<a1.size, a1.d[0], a1.d[1]>{};
constexpr auto b2 = B<a2.size, a2.d[0], a2.d[1], a2.d[2]>{};
template<typename T>
constexpr auto transform(const T& tuple) {
constexpr auto x1 = std::get<0>(tuple); // NOK
constexpr auto b1 = B<x1.size, x1.d[0], x1.d[1]>{}; // NOK
return std::tuple(b1);
}
constexpr auto t2 = transform(t1);
int main() {
}
The question is then: how can I make this sort of transformation. My idea is to write a meta-function with tuple t1
as parameter. But I can't get it right ...
Upvotes: 4
Views: 1383
Reputation: 1861
In C++17 you can pass a constexpr
lambda returning your argument:
constexpr auto t2 = transform([&] { return t1; });
Inside the function you can "call" the lambda and assign to a constexpr
:
template<class Tuple_>
constexpr auto transform(Tuple_ tuple_) {
constexpr auto tuple = tuple_();
// ...
Some research (thanks @wimalopaan) shows that this idiom has been described
http://coliru.stacked-crooked.com/a/073103acf18f80b6
#include <cstdint>
#include <iostream>
#include <tuple>
// not sure how robust this macro is...
#define CONSTEXPR_ARG(arg) [&] { return arg; }
template<auto N>
struct A {
inline static constexpr auto size = N;
const uint8_t d[N] {};
};
template<auto N, auto... II>
struct B {};
constexpr auto a1 = A<2>{1, 2};
constexpr auto a2 = A<3>{2, 3, 4};
constexpr auto t1 = std::tuple(a1, a2);
constexpr auto b1 = B<a1.size, a1.d[0], a1.d[1]>{};
constexpr auto b2 = B<a2.size, a2.d[0], a2.d[1], a2.d[2]>{};
template<class Tuple_>
constexpr auto transform(Tuple_ tuple_) {
constexpr auto tuple = tuple_();
constexpr auto x1 = std::get<0>(tuple); // NOK
constexpr auto b1 = B<x1.size, x1.d[0], x1.d[1]>{}; // NOK
return std::tuple(b1);
}
constexpr auto t2 = transform(CONSTEXPR_ARG(t1));
template<class T>
void inspect(const T& t) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main() {
inspect(t2);
}
Output:
void inspect(const T&) [with T = std::tuple<B<2, 1, 2> >]
Upvotes: 3