How is template metaprogramming working here (static const int value = 1 + StarCounter<\U>::value;) to print out 3 ?
#include <iostream>
template <typename T>
struct StarCounter
{
static const int value = 0;
};
template <typename U>
struct StarCounter<U*>
{
static const int value = 1 + StarCounter<U>::value;
};
int main()
{
std::cout << StarCounter<int***>::value << std::endl;//How is it printing 3?
return 0;
}
The first template creates a struct that will always return 0 when you call StarCounter<U>::value.
The second template specialises the first one for cases where a pointer is used. So when you call it with StarCounter<U*>::value, the second template is used, not the first and it will return StarCounter<U>::value + 1. Note that it removes the pointer at each recursion step.
So the call to StarCounter<int***>::value will expend to:
StarCounter<int***>::value // second template is used due to pointer
1 + StarCounter<int**>::value // second template is used due to pointer
1 + 1 + StarCounter<int*>::value // second template is used due to pointer
1 + 1 + 1 + StarCounter<int>::value // no pointer here, so first template is used
1 + 1 + 1 + 0
3
StarCounter<int>::value
equals 0, because it's matched with first instantiation of the template, where value is explicitly defined.
StarCounter<int*>::value = 1 + StarCounter<int>::value
equals 1, because StarCounter<int*> is matched with StarCounter<U*>. Yes, StarCounter<T> can also be considered as a match, but StarCounter<U*> is more specific and that's why this one is preferred.
Similarly,
StarCounter<int**>::value = 1 + StarCounter<int*>::value
equals 2 and
StarCounter<int***>::value = 1 + StarCounter<int**>::value
equals 3.
I find it helps to think of runtime equivalents when it comes to metaprogramming. In template metaprogramming, we use partial specialization, as in runtime programming, we use recursion. The primary template functions as the base case and the specializations function as the recursive cases.
Consider the following recursive version of determining the size of a container:
def size(x):
if empty(x):
return 0
else:
return 1 + size(tail(x))
This is the equivalent of the template code you present. The primary template, StarCounter<T>, is the base case. The empty case. It has size (value) zero. The specialization, StarCounter<U*>, is the recursive case. It has size (value) 1 plus the size of recursing with the tail (StarCounter<U>).
In C++17, we can even more explicitly make the metaprogramming version equivalent to the runtime recursive version (this is presented solely as an example and not as a way that this code should be written):
template <class T>
struct StarCounter {
static constexpr int calc_value() {
if constexpr (!std::is_pointer<T>::value) {
return 0;
}
else {
return 1 + StarCounter<std::remove_pointer_t<T>>::value;
}
}
static constexpr int value = calc_value();
};
There is a template StarCounter which in it's more general form has constant value equal to 0. So when you use this template for most of the types and ask for the value you will get 0.
This template has also a specialized version which accepts pointers.
It's implementation also has constant value which is equal to 1 (as we have a pointer which means we have at least one star) plus value of value of type which this pointer points to.
In case of three stars we have:
StarCounter<int***>::value = 1 + StarCounter<int**>::value (1) + StarCounter<int*>::value (1) + StarCounter<int>::value (0)
So I have a function that takes a variable length argument list, for example:
int avg(int count,...){
//stuff
}
I can call it with avg(4,2,3,9,4); and it works fine. It needs to maintain this functionality.
Is there a way for me to also call it with an array instead of listing the variables? For example:
avg(4,myArray[5]) such that the function avg doesn't see any difference?
No there is no such way. You can however make two functions, one that takes a variable number of arguments, and one that takes an array (or better yet, an std::vector). The first function simply packs the arguments into the array (or vector) and calls the second function.
void f() {}
template<typename T, std::size_t N>
void f(T array[N])
{
}
template<typename T, typename... Args>
void f(const T& value, const Args&... args)
{
process(value);
f(args...);
}
No. Since pointers are essentially unsigned integers it would not be able to tell the difference between a memory address and an unsigned integer. Alternatively (as I am sure you wanted to avoid), you would have to do:
avg( 4, myArray[ 0 ], ..., myArray[ 3 ] );
... where ... is myArray at positions 1 and 2 if you wanted to conform with the same parameters as your previous function. There are other ways to do this, such as using C++ vectors.
You can easily do it
struct{int arr[100];}p;
double avg2(int count,int* arr){
memcpy(&p,arr,count*sizeof(int));
return avg(count,p);
}
Better approach would be get rid of variadic arguments. This was inherited from C and it is a good practice to avoid it as much as possible.
Now your example avg(4,myArray[5]) is a bit fuzzy. I assume, that first argument defines how much items must be taken from array and second argument you planned to pass just an array. I assume this index operator is typo or limping method showing array size.
So you expect something like this:
int avg(int count, ...)
{
int sum = 0;
std::va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i) {
sum += va_arg(args, int);
}
va_end(args);
return sum / count;
}
template <size_t N, size_t... I>
int avg_helper(size_t count, const int (&arr)[N], std::index_sequence<I...>)
{
return avg(count, arr[I]...);
}
template <size_t N>
int avg(int count, const int (&arr)[N])
{
if (count > N)
throw std::invalid_argument { "to large count passed" };
return avg_helper(count, arr, std::make_index_sequence<N> {});
}
https://godbolt.org/z/7v1n7zaWq
Now note that in overload resolution variadic function is match as a last one. So when compiler can match template it will select it instead variadic function.
Note there is a trap. If you will pass a pointer (for example array decay) variadic argument function will kick in again. So as protection I've added extra overload which will trigger static_assert warning about array decay.
I think I understand how templates are evaluated lazily in C++ e.g. a la recursive replacements and a final simplification of the expansion. This typically limits the recursion depth available. I wonder if with the features new in C++11 (e.g. variadic templates or template packs) or with some Boost it is possible to force strict template evaluation. Or is this in principle impossible in C++?
Consider for example a template which sums all integer values 0..n:
template <int n>
struct sumAll { enum { value = n + sumAll<n-1>::value }; };
template <>
struct sumAll<0> { enum { value = 0 }; };
#include <iostream>
int main() { std::cout << sumAll<10000>::value << std::endl; }
Here sumAll<10>::value would be expanded to
sumAll<10>::value = 10 + sumAll<9>::value
= 10 + 9 + sumAll<8>::value
= 10 + 9 + 8 + sumAll<7>::value
= ...
= 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
and the final summation would only be performed once the template has been completely expanded. If that final expansion gets too long (e.g. in complex series expansions with many terms) the compiler will ultimately run out of space to store additional terms.
My question was in essence if there was a way to perform simplifications (like above summation) earlier.
You decide the recursion depth yourself. And just like normal recursion can cause stack overflows, template recursion can. But that's often fixable by a better recursive algorithm. Trivially:
template <int n>
struct sumAll { enum { value = n + n-1 + sumAll<n-2>::value }; };
template <>
struct sumAll<1> { enum { value = 0 }; };
template <>
struct sumAll<0> { enum { value = 0 }; };
Smarter:
template <int n>
struct sumAll { enum { value = (n*n+2)/2; };
Of course, you may complain that the latter is just being silly and real examples are more complex. But isn't that the whole problem? The compiler can't magically make that complexity go away for you.
C++ templates are turing-complete, which means that you use them to evaluate every computable function at compile time. It then follows from the halting theorem that
You cannot, in general, compute the amount of memory require to compile of a C++ program in advance. (I.e., there is no computable function which maps every C++ program to a memory bound for its compilation)
You cannot, in general, decide whether the compiler will ever finish instantiating template, or will go on forever.
So while you might be able to tweak a compiler to use less memory in some cases, you cannot solve the general problem of it running out of memory sometimes.
This is a more specific question based on a question I asked earlier...
If I have a function that takes two parameters (one required, one optional):
an STL container such as a vector
an "optional" comparison function that serves as a relational overload and returns the maximum value, whatever that is, in the vector...
Code:
template <typename Type>
Type FindMax (std::vector<Type> &myVec, int (*cmp)(Type one, Type two) = CallBack)
/.../
WHAT exactly, does the "int (*cmp)(Type one...)" say to the compiler? I want it to say, here's a function to use when comparing two of type Type...ie when using the relational operators <, >, =, etc. If no function is supplied by the user then use the default, otherwise, use what the user provides...
What exactly does the (*cmp)(Type one, Type two) say? Here's a pointer to a function that takes two parameters Type one and Type two? Is there any significance as to what comes after the *, ie could I write (*titsmagee)(Type one, Type two)? I'm assuming the naming convention is to help future readers?
For this to work with a "struct" does anything specific to the potential comparisons to be made need to be stored within said struct?
Thanks!
int (*cmp)(Type one, Type two)
The parameter named cmp is a pointer to a function returning int that takes two parameters of type Type.
struct Foo
{
int x;
};
int compare(Foo x, Foo y)
{
return (x.x == y.x) ? 0 : (x.x > y.x ? 1 : -1);
}
std::vector<Foo> vec;
FindMax<Foo>(vec, &compare);
You need cmp so you can call the comparison function inside FindMax:
template <typename Type>
Type FindMax (std::vector<Type> &myVec, int (*cmp)(Type one, Type two) = CallBack)
{
//whatever loop
max = cmp(myVec[i],myVec[j]) >= 0 ? myVec[i] : myVec[j];
}
EDIT Breaking down the return:
return (x.x == y.x) ? 0 : (x.x > y.x ? 1 : -1);
?: is the ternary conditional operator.
condition ? expression1 : expression2
returns (loosely speaking) expression1 if condition is true, expression2 otherwise.
So what that means is:
if (x.x == y.x)
return 0;
else
if (x.x > y.x)
return 1;
else
return -1;
It's what you expect the comparison function to do. Return 0 for equality, 1 if the first element is bigger than the second, and -1 for the inverse.
EDIT 2
struct Foo
{
int x;
};
//Foo has a member x.
Foo f;
//Create a Foo object called f.
f.x;
//Access the member x of the object
C++ Notes: Array Initialization has a nice list over initialization of arrays. I have a
int array[100] = {-1};
expecting it to be full with -1's but its not, only first value is and the rest are 0's mixed with random values.
The code
int array[100] = {0};
works just fine and sets each element to 0.
What am I missing here.. Can't one initialize it if the value isn't zero ?
And 2: Is the default initialization (as above) faster than the usual loop through the whole array and assign a value or does it do the same thing?
Using the syntax that you used,
int array[100] = {-1};
says "set the first element to -1 and the rest to 0" since all omitted elements are set to 0.
In C++, to set them all to -1, you can use something like std::fill_n (from <algorithm>):
std::fill_n(array, 100, -1);
In portable C, you have to roll your own loop. There are compiler-extensions or you can depend on implementation-defined behavior as a shortcut if that's acceptable.
There is an extension to the gcc compiler which allows the syntax:
int array[100] = { [0 ... 99] = -1 };
This would set all of the elements to -1.
This is known as "Designated Initializers" see here for further information.
Note this isn't implemented for the gcc c++ compiler.
The page you linked to already gave the answer to the first part:
If an explicit array size is
specified, but an shorter
initiliazation list is specified, the
unspecified elements are set to zero.
There is no built-in way to initialize the entire array to some non-zero value.
As for which is faster, the usual rule applies: "The method that gives the compiler the most freedom is probably faster".
int array[100] = {0};
simply tells the compiler "set these 100 ints to zero", which the compiler can optimize freely.
for (int i = 0; i < 100; ++i){
array[i] = 0;
}
is a lot more specific. It tells the compiler to create an iteration variable i, it tells it the order in which the elements should be initialized, and so on. Of course, the compiler is likely to optimize that away, but the point is that here you are overspecifying the problem, forcing the compiler to work harder to get to the same result.
Finally, if you want to set the array to a non-zero value, you should (in C++, at least) use std::fill:
std::fill(array, array+100, 42); // sets every value in the array to 42
Again, you could do the same with an array, but this is more concise, and gives the compiler more freedom. You're just saying that you want the entire array filled with the value 42. You don't say anything about in which order it should be done, or anything else.
C++11 has another (imperfect) option:
std::array<int, 100> a;
a.fill(-1);
With {} you assign the elements as they are declared; the rest is initialized with 0.
If there is no = {} to initalize, the content is undefined.
Using std::array, we can do this in a fairly straightforward way in C++14. It is possible to do in C++11 only, but slightly more complicated.
Our interface is a compile-time size and a default value.
template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
return std::array<std::decay_t<T>, 0>{};
}
template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}
template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}
The third function is mainly for convenience, so the user does not have to construct a std::integral_constant<std::size_t, size> themselves, as that is a pretty wordy construction. The real work is done by one of the first two functions.
The first overload is pretty straightforward: It constructs a std::array of size 0. There is no copying necessary, we just construct it.
The second overload is a little trickier. It forwards along the value it got as the source, and it also constructs an instance of make_index_sequence and just calls some other implementation function. What does that function look like?
namespace detail {
template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
// Use the comma operator to expand the variadic pack
// Move the last element in if possible. Order of evaluation is well-defined
// for aggregate initialization, so there is no risk of copy-after-move
return std::array<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}
} // namespace detail
This constructs the first size - 1 arguments by copying the value we passed in. Here, we use our variadic parameter pack indexes just as something to expand. There are size - 1 entries in that pack (as we specified in the construction of make_index_sequence), and they have values of 0, 1, 2, 3, ..., size - 2. However, we do not care about the values (so we cast it to void, to silence any compiler warnings). Parameter pack expansion expands out our code to something like this (assuming size == 4):
return std::array<std::decay_t<T>, 4>{ (static_cast<void>(0), value), (static_cast<void>(1), value), (static_cast<void>(2), value), std::forward<T>(value) };
We use those parentheses to ensure that the variadic pack expansion ... expands what we want, and also to ensure we are using the comma operator. Without the parentheses, it would look like we are passing a bunch of arguments to our array initialization, but really, we are evaluating the index, casting it to void, ignoring that void result, and then returning value, which is copied into the array.
The final argument, the one we call std::forward on, is a minor optimization. If someone passes in a temporary std::string and says "make an array of 5 of these", we would like to have 4 copies and 1 move, instead of 5 copies. The std::forward ensures that we do this.
The full code, including headers and some unit tests:
#include <array>
#include <type_traits>
#include <utility>
namespace detail {
template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
// Use the comma operator to expand the variadic pack
// Move the last element in if possible. Order of evaluation is well-defined
// for aggregate initialization, so there is no risk of copy-after-move
return std::array<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}
} // namespace detail
template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
return std::array<std::decay_t<T>, 0>{};
}
template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}
template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}
struct non_copyable {
constexpr non_copyable() = default;
constexpr non_copyable(non_copyable const &) = delete;
constexpr non_copyable(non_copyable &&) = default;
};
int main() {
constexpr auto array_n = make_array_n<6>(5);
static_assert(std::is_same<std::decay_t<decltype(array_n)>::value_type, int>::value, "Incorrect type from make_array_n.");
static_assert(array_n.size() == 6, "Incorrect size from make_array_n.");
static_assert(array_n[3] == 5, "Incorrect values from make_array_n.");
constexpr auto array_non_copyable = make_array_n<1>(non_copyable{});
static_assert(array_non_copyable.size() == 1, "Incorrect array size of 1 for move-only types.");
constexpr auto array_empty = make_array_n<0>(2);
static_assert(array_empty.empty(), "Incorrect array size for empty array.");
constexpr auto array_non_copyable_empty = make_array_n<0>(non_copyable{});
static_assert(array_non_copyable_empty.empty(), "Incorrect array size for empty array of move-only.");
}
The page you linked states
If an explicit array size is specified, but an shorter initiliazation list is specified, the unspecified elements are set to zero.
Speed issue: Any differences would be negligible for arrays this small. If you work with large arrays and speed is much more important than size, you can have a const array of the default values (initialized at compile time) and then memcpy them to the modifiable array.
Another way of initializing the array to a common value, would be to actually generate the list of elements in a series of defines:
#define DUP1( X ) ( X )
#define DUP2( X ) DUP1( X ), ( X )
#define DUP3( X ) DUP2( X ), ( X )
#define DUP4( X ) DUP3( X ), ( X )
#define DUP5( X ) DUP4( X ), ( X )
.
.
#define DUP100( X ) DUP99( X ), ( X )
#define DUPx( X, N ) DUP##N( X )
#define DUP( X, N ) DUPx( X, N )
Initializing an array to a common value can easily be done:
#define LIST_MAX 6
static unsigned char List[ LIST_MAX ]= { DUP( 123, LIST_MAX ) };
Note: DUPx introduced to enable macro substitution in parameters to DUP
For the case of an array of single-byte elements, you can use memset to set all elements to the same value.
There's an example here.
The simplest way is to use std::array and write a function template that will return the required std::array with all of its element initialized with the passed argument as shown below.
C++11 Version
template<std::size_t N> std::array<int, N> make_array(int val)
{
std::array<int, N> tempArray{};
for(int &elem:tempArray)
{
elem = val;
}
return tempArray;
}
int main()
{
//---------------------V-------->number of elements
auto arr = make_array<8>(5);
//------------------------^---->value of element to be initialized with
//lets confirm if all objects have the expected value
for(const auto &elem: arr)
{
std::cout << elem << std::endl; //prints all 5
}
}
Working demo
C++17 Version
With C++17 you can add constexpr to the function template so that it can be used in constexpr context:
//-----------------------------------------vvvvvvvvv--->added constexpr
template<std::size_t N> std::array<int, N> constexpr make_array(int val)
{
std::array<int, N> tempArray{};
for(int &elem:tempArray)
{
elem = val;
}
return tempArray;
}
int main()
{
//--vvvvvvvvv------------------------------>constexpr added
constexpr auto arr = make_array<8>(5);
for(const auto &elem: arr)
{
std::cout << elem << std::endl;
}
}
Working demo
1) When you use an initializer, for a struct or an array like that, the unspecified values are essentially default constructed. In the case of a primitive type like ints, that means they will be zeroed. Note that this applies recursively: you could have an array of structs containing arrays and if you specify just the first field of the first struct, then all the rest will be initialized with zeros and default constructors.
2) The compiler will probably generate initializer code that is at least as good as you could do by hand. I tend to prefer to let the compiler do the initialization for me, when possible.
In the C++ programming language V4, Stroustrup recommends using vectors or valarrays over builtin arrays. With valarrary's, when you create them, you can init them to a specific value like:
valarray <int>seven7s=(7777777,7);
To initialize an array 7 members long with "7777777".
This is a C++ way of implementing the answer using a C++ data structure instead of a "plain old C" array.
I switched to using the valarray as an attempt in my code to try to use C++'isms v. C'isms....