Reputation: 157
template<unsigned int size>
struct Vec {
Vec() = default;
};
auto build_vec(unsigned int size) {
return Vec<size>();
}
int main() {
auto vec = build_vec(5);
return 0;
}
This program doesn't compile as non-type template argument is not a constant expression
. Basically, the size
parameter sent into build_vec
is not known to the compiler during compilation type.
Then I wonder, can I add some keyword to force size
to be evaluated during compile time thus struct Vec
can be built through a function?
Upvotes: 0
Views: 184
Reputation: 1193
It does NOT fit your expectation completely but rely on boost hana approach we may have similar one. Below is an example using variable template
#include <iostream>
template<unsigned int size>
struct Vec {
Vec() = default;
~Vec() {std::cout << size << '\n';}
};
template <unsigned int i>
constexpr std::integral_constant<unsigned int, i> uint_c{};
template <unsigned int i>
auto build_vec(std::integral_constant<unsigned int, i>) {
return Vec<i>();
}
int main() {
const size_t n = 5;
auto vec = build_vec(uint_c<n>);
return 0;
}
Upvotes: 1
Reputation: 29975
my code base constrains me that it has to be a function parameter, not template parameter.
That's not possible. Return type of a function cannot be dependent on runtime values. Your options are:
Vec
a runtime value as well.std::any
, etc), have the Vec
class derive from some base class, or not return the object. Don't do this if the range is too large. It may generate lots of code-bloat:#include <cstdio>
#include <utility>
template <unsigned size>
struct Vec {
Vec() = default;
void use_value() { std::printf("My constexpr value is %u\n", size); }
};
template <unsigned ct_val>
void build_vec_impl_impl() {
Vec<ct_val> cant_return;
cant_return.use_value();
}
template <unsigned... vals>
void build_vec_impl(std::integer_sequence<unsigned, vals...>, unsigned rt_val) {
using fp_builder = void (*)();
constexpr fp_builder builders[]{build_vec_impl_impl<vals>...};
builders[rt_val]();
}
template <unsigned max>
void build_vec(unsigned const rt_val) {
using seq = std::make_integer_sequence<unsigned, max + 1>;
build_vec_impl(seq{}, rt_val);
}
int main() {
auto constexpr max = 10;
for (unsigned i = 0; i < max; ++i) build_vec<max>(i);
}
3. Use a dynamic language like Python where return type may depend on runtime values
Upvotes: 0
Reputation: 122458
No, this is not possible. A functions parameter is not known at compile time. The common way to signal that size
must be known at compile time is to make the function a template and size
a template parameter:
template<unsigned int size>
struct Vec {
Vec() = default;
};
template <unsigned int size>
auto build_vec() {
return Vec<size>();
}
int main() {
auto vec = build_vec<5>();
}
Though, now it should be obvious that the function does not help to turn a runtime value into a compile time value. In general thats not possible, unless you implement such mapping manually. You don't need build_vec
because the caller can use auto vec = Vec<size>();
directly.
Upvotes: 1