Given a template
template <int n>
void f(){...};
I know I can specialize it for specific values of n by doing:
template <>
void f<2>(){...};
But, is there a method which allows me to specialize it for all positive n?
I thought of doing the following
template <int n>
void f<n>(){
int dummy[n]; //invalid for n < 0
...
};
So for n<0 this code is invalid and the compiler would resort to the previous definition. Unfortunately, all I get is a redefinition of 'void f<n>()' error.
Note: I'm guessing this is probably not supported by the standard. I'm asking if there isn't some method (maybe some template metaprogramming) to achieve this effect.
One option would be to use another level of indirection. Define an auxiliary template that takes in two arguments - the number n and a bool representing whether or not n is negative, then specialize that template for when n is negative. Then, have your f function instantiate the template with the right arguments.
For example:
template <int n, bool isNegative> struct fImpl {
static void f() {
/* ... code for when n is positive ... */
}
};
template <int n> struct fImpl<n, true> {
static void f() {
/* ... code for when n is negative ... */
}
};
template <int n> void f() {
fImpl<n, (n < 0)>::f();
}
Another option is to use SFINAE overloading and the std::enable_if template class from C++11 (or Boost's equivalent);
template <int n> void f(typename std::enable_if<(n < 0)>::type* = 0) {
/* ... n is negative ... */
}
template <int n> void f(typename std::enable_if<(n >= 0)>::type* = 0) {
/* ... n is positive ... */
}
Each of these functions will only be available for overload resolution if n has the proper sign, so the correct version will always be called.
Hope this helps!
Related
Let's consider the following code for compile-time evaluation of the factorial function:
#include <concepts>
template <std::integral auto num>
struct factorial {
constexpr static auto val{num * factorial<num - 1>::val};
};
// Note: This only specializes the class for (int)0
template <>
struct factorial<0> {
constexpr static auto val{1};
};
// ...
factorial<4>::val; // Ok: 24
factorial<4u>::val; // error: template instantiation depth exceeds maximum of 900
// This makes sense: There's no factorial<0u> specialization.
Is there a way to introduce specialization factorial<0> for all integral types (i.e. for all the types that satisfy std::integral)?
Of course, I'd like to avoid actually writing out specializations factorial<0u>, factorial<0l>, and so on.
Instead of explicitly specializing for specifically 0 (i.e. an int with value 0), you can partially specialize for any value which compares equal to 0:
template <std::integral auto I> requires (I == 0)
struct factorial<I> {
static constexpr auto val = 1;
};
which if you prefer can also be spelled this way:
template <class T, T I> requires (I == 0)
struct factorial<I> {
static constexpr auto val = 1;
};
but I don't think there's a way to deduce T{0} as the value.
template <unsigned int n>
class myclass {};
Is there a way (preferably using SFINAE, that is std::enable_if) to get compilation error when n is odd? I need it to be even.
If you want to do it with SFINAE, use partial template specialization and don't define the base class.
e.g.:
template <unsigned int n, typename _ = void>
class myclass;
template <unsigned int n>
class myclass<n,std::enable_if_t<n%2==0>> {};
then you'll get a compile-time error if you try to instantiate myclass with an odd number.
(example godbolt)
Another approach would be to just use a static_assert to check if the number is even, this has the additional benefit that you can specify a message instead of getting a cryptic SFINAE error:
template <unsigned int n>
class myclass {
static_assert(n%2==0, "n must be even");
};
(example godbolt)
If you want you can also combine the two variants above, giving you an SFINAE solution with a nice error message:
template <unsigned int n, typename _ = void>
class myclass {
static_assert(n!=n, "n must be even");
};
template <unsigned int n>
class myclass<n,std::enable_if_t<n%2==0>> {
/* code */
};
(godbolt example)
In case you're using a c++ version before C++14 you'll need to replace
std::enable_if_t<?>
with
typename std::enable_if<?>::type
in the above examples.
preferably using SFINAE
If you need SFINAE, I suggest creating a type trait:
template<unsigned n>
static constexpr bool is_even_v = n % 2 == 0;
template <unsigned int n, std::enable_if_t<is_even_v<n>, int> = 0>
class myclass {};
Demo
Suppose, we have
template <int> struct Node;
It is required to get "reusable" compile-time function, which counts all Node specializations, defined exactly before every call of that function (from different points of translation unit). That is, number of specializations before point of function template instantiation. To simplify solution suppose that Node specializations are introduced sequentionally, starting from zero: 0,1,2,3...
Ok, here is C++ code:
#include <type_traits>
template <typename T> decltype(T{}) InstanceOf(int);
template <typename T> void InstanceOf(...);
template <typename K, template <int> typename T, int N = 0,
typename = decltype(InstanceOf<T<N>>(0))>
struct NCount
: NCount<K, T, N + 1> {};
template <typename K, template <int> typename T, int N>
struct NCount<K, T, N, void>
: std::integral_constant<int, N> {};
template <int> struct Node;
template <typename K = void, template <int> typename T = Node>
constexpr auto Count()
{
return NCount<K, T>::value;
}
template <> struct Node<0> {};
template <> struct Node<1> {};
int main()
{
return Count(); //expected: 2
}
template <> struct Node<2> {};
Almost any code modification results in issue for some/all compilers (gcc/clang 9+ is interesting first of all):
1. if Count() body is not fully-dependent from template typename list, gcc fails:
template <typename K = void>
constexpr auto Count()
{
return NCount<K, Node>::value; //main: 0 returned
}
"Workaround" is to move the first specialization (Node<0>) before Count() template definition:
template <> struct Node<0> {};
template <typename K = void>
constexpr auto Count()
{
return NCount<K, Node>::value; //main: 2 returned
}
FYI: if K is removed from inside body in this case, we get another result (like body pre-compiled "in the place" with knowledge about single Node specialization):
template <> struct Node<0> {};
template <typename K = void>
constexpr auto Count()
{
return NCount<void, Node>::value; //main: 1 returned
}
2. if Count() return value type is specified (it is known - int), then totally all specializations is counted by both compilers:
template <typename K = void, template <int> typename T = Node>
constexpr int Count()
{
return NCount<K, T>::value; //main: 3 returned
}
Seems, that understanding function signature, compiler just "puts the call" of Count() inside main, but body of the function template will be compiled "later", after all cpp-file content is parsed (plus Node<2> spec). So the "auto" is the way to make compiler calculate NCount exactly in POI to get desired number.
Note that K-type purpose is to provide ability to be called as many times as required from any point of code. K-type must be unique every time (with respect to all other Count<K>() calls) to get actual value.
The questions are:
is there any compiler bug (including "modification" comments);
is this solution ill-formed (where);
if yes, could you give c++ standard compliant reliable solution?
p.s. I know about standard paragraphs, which tell us that class template specialization could not be used in some point if it is not defined before. But. Note that Count() first of all gets knowledge about available specializations before doing smth (indeed, in this example - no processing). Moreover, Node class main template just can not be used if not specialized - it has no definition! So...
p.s.s. In fact, all gcc/clang 5+ and icc give desirable 2. MSVC gives 0. Other [more specific] compilers give 0 also. Checked via godbolt.org, wandbox.org.
Thanks!
I am trying to learn more about templates in C++. I would like to be able to call a function where I pass it a type and the length as an argument. Is this possible?
template <class T>
void alloc_arr (int l) {
std::allocator<T[l]> a;
}
alloc_arr<int[]>(64);
It doesn't work because the instantiated type must be fixed at compile time (T[l] is not fixed).
Is there some other way to do this which doesn't require the length to be specified in the type (<T[64]>)?
Is there some other way to do this which doesn't require the length to be specified in the type ()?
In some way, you need to pass it as template parameter
You can pass it explicitly, as suggested by Lourens Dijkstra
template <typename T, std::size_t Dim>
void alloc_arr ()
{
std::allocator<T[Dim]> a;
// ...
}
or, if you can use at least C++11, also you can deduce it from the type of an argument; by example,
template <typename T, std::size_t Dim>
void alloc_arr (std::integral_constant<std::size_t, Dim> const &)
{
std::allocator<T[Dim]> a;
// ...
}
or also
template <typename T, typename U>
void alloc_arr (U const &)
{
std::allocator<T[U::value]> a;
// ...
}
calling alloc_arr with a std::integral_constant<std::size_t, 5u>{}, by example.
You could pass the size as a template parameter:
template <class T, size_t size>
void alloc_arr() { ... }
This is the only way. A couple of days ago I found out that passing a constexpr lambda as a regular parameter is considered ill-formed: Trying to pass a constexpr lambda and use it to explicitly specify returning type
Also, note that type T should be int; not int[].
So, calling alloc_arr:
alloc_arr<int, 64>();
This is related to my earlier post. I'd like to know why one attempted solution didn't work.
template <typename... T> /* A */
size_t num_args ();
template <>
size_t num_args <> ()
{
return 0;
}
template <typename H, typename... T> /* B */
size_t num_args ()
{
return 1 + num_args <T...> ();
}
If I try to call, say, num_args<int,float>() then the error is that the function call is ambiguous:
A with T={int,float}
B with H=int, T={float}
I don't understand how this is ambiguous -- A is a declaration and B is a definition of the function declared by A. Right?
I'm trying to make this example work and the responses to my earlier question seem to claim that it can never work.
If that's the case, what's the point of variadic free functions? What can they do?
I don't understand how this is ambiguous -- A is a declaration and B
is a definition of the function declared by A. Right?
No. A is a declaration of a function template, and B is a declaration (and definition) of another function template.
The compiler has no way to decide between the two: they both have no arguments, and the template arguments are a match for both.
The one in the middle is an explicit total specialization of the function template declared in A.
If you tried to make B another specialization of A:
template <typename H, typename... T> /* B */
size_t num_args<H, T...>()
{
return 1 + num_args <T...> ();
}
... you'd end up with a partial specialization of a function template, which is not allowed.
You can do this with the usual trick of using a class template with partial specializations and a function template that calls into the class template:
template <typename... T>
class Num_Args;
template <>
struct Num_Args <>
{
static constexpr size_t calculate() {
return 0;
}
};
template <typename H, typename... T>
struct Num_Args <H, T...>
{
static constexpr size_t calculate() {
return 1 + Num_Args<T...>::calculate();
}
};
template <typename... T> /* B */
constexpr size_t num_args ()
{
return Num_Args<T...>::calculate();
}
Apropos the usefulness/uselessness of free variadic function templates: the usual use case for these is to have a variadic function parameter list, in which case a regular overload for the empty case will do just fine:
size_t num_args()
{
return 0;
}
template <typename H, typename... T> /* B */
size_t num_args (H h, T... t)
{
return 1 + num_args(t...);
}
EDIT:
As far as I can see, the following abuse of enable_if ought to work as a solution to your original question:
#include <utility>
// Only select this overload in the empty case
template <typename... T>
typename std::enable_if<(sizeof...(T) == 0), size_t>::type
num_args()
{
return 0;
}
template <typename H, typename... T>
size_t
num_args()
{
return 1 + num_args<T...>();
}
(Edit2: Reversed the order of the overloads to make the code actually compile)
While I really like the std::enable_if<sizeof...(T) == 0, _> hack by JohannesD, I'll still drop the below hack that I don't actually remember where I learned from, which resolves the ambiguity with only free functions without having to use classes:
template <typename One>
size_t num_args() {
return 1;
}
template <typename First, typename Next, typename... Rest>
size_t num_args() {
return 1 + num_args<Next, Rest...>();
}
No partial specialization required, and it totally avoids the zero parameter case by ending the unpacking recursion at one parameter. Also, see https://stackoverflow.com/a/58295007/1525238 for an even nicer c++17 solution that uses the same idea.
The only catch is that it actually doesn't cover the zero template parameter case, which is impossible in the context of free functions AFAIK. If that is required from the consumer's perspective, a partially specialized class must be used, see R. Martinho Fernandes' answer.
As for the utility of variadic template free functions, I find them particularly useful as constexpr type-safe accumulating calculator utilities.