How to feed vector elements to a template - c++

I need to use a list of elements of the same type as a template argument so I'm using a vector but I'm not sure how to make this work
#include <iostream>
#include <cstdint>
#include <vector>
template <uint8_t VAL>
void foo()
{
std::cout << "__" << std::endl;
};
template <>
void foo<3>()
{
std::cout << "OK" << std::endl;
};
int main()
{
std::vector<uint8_t> v = { 2, 4, 5, 2, 3, 55 };
for (auto &k : v) {
foo<k>();
}
return (0);
}
the compiler basically complains about k not being a constant expression, the problem is that I have no idea about how to modify this to make this work, I need some data structure to iterate on, so I need to keep the vector, I need a template to simplify my life, so the more I see this the more I feel trapped in an infinite loop.

You could use a variadic template to get rid of actually storing your list in a vector, so you'd just pass the values directly to the variable function template:
#include <iostream>
void print(int t) {
static char const *s [] = { "__", "OK" };
std::cout << s[t == 3];
}
void print() {}
template<typename... Args>
void print(int n, Args ... args) {
print(n);
print(args...);
}
int main() {
print(2, 4, 5, 2, 3, 55);
}
Result:
________OK__
As you can see, however, this still has to evaluate equality to 3 at run-time. I hesitate to say it can't be done with template specialization, but at least offhand, I don't see how to do it, if its possible.

You shouldn't be using a template if whatever needs to go <here> cannot be deduced on compile time trivially. In this case, k is not a constant expression, so you cannot use it as a template argument.
Templates are not a magic hammer. They have a lot of use-cases, but you can't use them for absolutely everything.
In this particular snippet of code, foo should be defined as void foo(uint8_t).
yes, infact my problem is how to turn that vector into a constant-compile-time set of values, the real problem it's not really about templates.
You might be able to pull this off using variadic templates. Instead of using the vector, you would use the integral constants directly in a variadic template (foo<2, 4, 5, 2, 3, 55>).
I'm not very keen on them, so this'll take a while.
edit: Jerry beat me to it.

If you really want a way to iterate over a compile-time constant list of integral values:
#include <iostream>
#include <cstdint>
template <uint8_t VAL>
inline void foo()
{
std::cout << "__" << std::endl;
}
template <>
void foo<3>()
{
std::cout << "OK" << std::endl;
}
template <uint8_t... Values>
struct FooHelper {
static void foo_all() {
}
};
template <uint8_t First, uint8_t... Rest>
struct FooHelper<First, Rest...> {
static void foo_all() {
foo<First>();
FooHelper<Rest...>::foo_all();
}
};
template <uint8_t... Values>
void foo_all()
{
FooHelper<Values...>::foo_all();
}
int main()
{
foo_all<2, 4, 5, 2, 3, 55>();
}
Although I honestly don't see the use case for it.

The compiler has no possibility to infer the possible values for k at compile time, so I can't see how this could work ?

Nope, that won't work for non-constant expressions. Just make it a plain old function:
#include <iostream>
#include <cstdint>
#include <vector>
void foo(uint8_t VAL)
{
if(VAL == 3)
std::cout << "OK" << std::endl;
else
std::cout << "__" << std::endl;
};
int main()
{
std::vector<uint8_t> v = { 2, 4, 5, 2, 3, 55 };
for (auto &k : v) {
foo(k);
}
return (0);
}

Related

Can we iterate through an array passed to a function using for-each loop?

I know we can iterate through an array passed as an argument in this way:
// NO ERROR
void fun(int *a, int n){
for(int i=0; i<n; i++)
cout<<a[i];
}
But, is there any way I could iterate through an array using a for-each loop inside a function like this?
// ERROR
void fun(int *a, int n){
for(auto x:a)
cout<<x;
}
A pointer is not an array. If you pass a pointer to the first element of an array to a function then its no longer an array, but a pointer.
You can use a range based loop when you pass the array by reference:
#include <iostream>
template <size_t N>
void foo(int (&x)[N]) {
for (int i : x) std::cout << i << " ";
}
int main() {
int x[] = {1,2,3};
foo(x);
}
Output:
1 2 3
This works, because the range based loop uses std::begin(x) and std::end(x) to get iterators to the begin and end of the array. Pointers don't have a begin or end.
In C++20, you can use std::span:
#include <cstddef>
#include <cstdio>
#include <span>
void foo(int* arr, std::size_t sz) {
std::span<int> span{arr, sz};
for (int elm : span) {
std::printf("%d\n", elm);
}
}
Or you could make span the input argument in the first place:
void foo(std::span<int> span) {
for (int elm : span) {
std::printf("%d\n", elm);
}
}
If the signature of the function is flexible, I suggest you use the second option.
Pre C++20, here is an implementation of span from GSL. Or make your own wrapper class with begin() and end() functions.
Alternative non-template C++20 solution:
auto range = std::views::counted(arr, sz);
for (auto elm : range) {
The benefit of this compared to std::span is that this is more general and works with any iterator, not requiring a contiguous iterator such as a pointer.
The benefit of using std::span instead of this is that you can use std::span as the function parameter without making it a template.
Alternative template solution (works pre C++20):
template <class Range>
void foo(const Range& range) {
for (auto elm : range) {
The benefit of this compared to int (&arr)[N] is that it is much more general. This template works with all ranges.
Besides range-for, you could consider avoiding the loop entirely (works pre C++20):
auto print = [](auto elm) {
std::cout << elm;
}
std::for_each_n(arr, sz, print);
I recommend this if you don't have C++20, cannot have boost / ranges / GSL libraries for some reason, and cannot have a template.
yes, you can. Just pass the array by reference to a template function:
#include <iostream>
using namespace std;
template <size_t N> void foo(int (&arr)[N])
{
for (auto i:arr)
cout << i << " ";
}
int main()
{
int array[] = { 5, 17, 3452, 546546, 756756, 75675, 756753, 345, 53};
foo(array);
return 0;
}
And the real answer:
int made[] = {10 , 2 ,15};
std::for_each(std::begin(made),std::end(made),[=](auto x){ std::cout << x << std::endl; });
You can parallelize std::for_each with say std::execution::par.
With function code will be:
#include <iostream>
#include <vector>
#include <execution>
void f(int (&made)[3])
{
std::for_each(std::begin(made),std::end(made),[=](auto x){ std::cout << "and then " << x << std::endl; });
}
int main(int argc , char *argv[])
{
int made[] = {10 , 2 ,15};
f(made);
}

Passing arguments to another variadic function

Is there any way at all for this code to compile and work as intended without resorting to va_list stuff ?
#include <iostream>
void fct(void)
{
std::cout << std::endl;
}
void fct(int index, int indexes...)
{
std::cout << index << ' ';
fct(indexes); //or fct(indexes...); ?
}
int main(void)
{
fct(1, 2, 3, 4, 5, 6, 7);
return 0;
}
I suspect you have misunderstood the meaning of the signature
void fct (int index, int indexes...)
I suspect you think that fct() expect a int single value (index) and a variadic list of int's (indexex...) with C++11 style of parameter pack expansion.
No: it's the same as
void fct (int index, int indexes, ...)
so two int single values and a C-style of optional argument that you can use only through va_list stuff.
If you don't believe it, try calling fct() with only an integer argument
fct(1);
You should obtain an error of type "error: no matching function for call to 'fct'" with a note of type "note: candidate function not viable: requires at least 2 arguments, but 1 was provided" regarding the variadic version of fct().
If you want receive a variadic list of parameters and recursively pass the to the same function, you can use the template variadic way.
By example
template <typename ... Ts>
void fct(int index, Ts ... indexes)
{
std::cout << index << ' ';
fct(indexes...);
}
If you really dislike the idea of a template, I guess you could cheat a bit like this:
#include <iostream>
#include <vector>
void fct(std::vector<int>&& _indices)
{
for (auto&& i : _indices)
{
std::cout << i << ' ';
}
std::cout << std::endl;
}
int main(void)
{
fct({1, 2, 3, 4, 5, 6, 7}); // Note the curly braces
return 0;
}

How to check if a data type is an array? (C++)

So I am currently a student and have run into the following exercise:
Write a function that prints the elements in an array. The array is sent to the function by argument. If this argument is not an array, an exception of type invalid_argument must be thrown. Test the function in the main() function.
So my code is currently as follows:
#include <iostream>
#include <exception>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::invalid_argument;
using std::string;
template<class T>void printArray(T arr){
try{
arr.size();
}
catch(...){
for (int i=0; i < sizeof(arr); i++){
cout << arr[i] << endl;
}
}
throw invalid_argument("Argument not of type array");
};
int main(){
string arrChars[5] = {"1", "2", "3", "John", "5"};
string s = "Jack";
try{
printArray(arrChars);
}
catch(invalid_argument &e){
cout << "Error: " << e.what() << endl;
}
return 0;
}
This is after already trying other options such as:
template<class T>void printArray(T arr[]){
...
}
Which doesn't allow the program to run either as I cannot pass any arguments to the printArray() function that are not arrays.
My plan with the code is to swap out arrChars and s as the arguments to printArray() in order to determine success off the program.
If this argument is not an array, an exception of type invalid_argument must be thrown.
That's... a weird thing to want to do in C++. Typically, we'd go for "if this argument is not an array, the code should not compile." But hey, we can do that too. Just write one function overload that takes an array, and one that takes anything:
template <typename T, size_t N>
void printArray(const T (&arr)[N]) {
// print array of size N here
}
template <typename T>
void printArray(const T& ) {
throw invalid_argument("Argument not of type array");
}
Try something like this
#include <iostream>
#include <type_traits>
#include <stdexcept>
#include <vector>
template <class T>
void printArray( const T &a )
{
if ( !std::is_array<T>::value ) throw std::invalid_argument("Argument not of type array");
for ( const auto &x : a ) std::cout << x << std::endl;
}
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
try
{
printArray( a );
printArray( v );
}
catch ( const std::invalid_argument &e )
{
std::cout << e.what() << std::endl;
}
}
The program output is
0
1
2
3
4
5
6
7
8
9
Argument not of type array
"Write a function that prints the elements in an array"
When you say "array", Are we talking about C[] array or std::array.
Assuming that you are talking about std::array you could write a single template method expecting one argument of any type.
If it is std::array that you are talking about then its totally understandable and possible. Here is a possible solution.
Use a dynamic_cast or typeid to check the type of the argument received.
template <typename T> void printArray(const T& arrayArgument) {
if (std::array<int>& test == dynamic_cast<std::array<int>&>(arrayArgument))
{/* do whatever */ }
}
or
if(typeid(arrayArgument) == typeid(std::array<int>))
Find more information on dynamic_cast and typeid in the following post.
C++ dynamic_cast vs typeid for class comparison
And if you are thinking of using C[] arrays then this post might help you rethink.
Container Classes over legacy C[] arrays

Functors in static global arrays

I've been trying to figure out how to properly pair a function with an id. What I've been doing so far is a C-way of doing it:
#include <iostream>
void PrintA();
void PrintB();
struct Function
{
int id;
void (*function)();
};
static const Function functions[] =
{
{1, PrintA},
{2, PrintB},
{0, 0}
};
void PrintA()
{
std::cout << "A" << std::endl;
};
void PrintB()
{
std::cout << "B" << std::endl;
};
int main()
{
int id = 1;
for(int i = 0; functions[i].function != 0 ; i++)
{
if(functions[i].id == id)
{
functions[i].function();
}
}
}
I'm trying to achieve the same functionality using functors in C++. I suppose I need to use inheritance to be able to store the different functions in the same array meaning I also need to use pointers for the array in order to prevent slicing. Is the following way of doing this the correct way and are there any alternatives?
Also is there any simpler version to call the operator than how I did it?
#include <iostream>
#include <memory>
class Base
{
public:
virtual void operator()() = 0;
};
class PrintA : public Base
{
public:
void operator()();
};
void PrintA::operator()()
{
std::cout << "A" << std::endl;
}
class PrintB : public Base
{
public:
void operator()();
};
void PrintB::operator()()
{
std::cout << "B" << std::endl;
}
struct Functor
{
int id;
std::shared_ptr<Base> function;
};
static Functor functors[] =
{
{1, std::shared_ptr<Base>(new PrintA)},
{2, std::shared_ptr<Base>(new PrintB)},
{0, 0}
};
int main()
{
int id = 2;
for(int i = 0; functors[i].function != 0 ; i++)
{
if(functors[i].id == id)
{
functors[i].function->operator()();
}
}
}
EDIT: I have to use a rather old GCC version making it impossible to use c++11 features. Boost is available, though. I suppose an std::map would be a good idea, but what I was really asking (didn't really make it clear) was that is there a better way to store the functions than shared_ptr. I suppose that std::function/boost::function way is the way to do it.
In C++11 (or Boost, if you're stuck in the past), this kind of type erasure is available in the function wrapper; and there's always been map to perform the ID-based lookup. So your example is as simple as:
#include <map>
#include <functional>
#include <iostream>
// Note: This will be a lot messier if you're stuck with a pre-2011 compiler.
// You'll need to define the functors (or functions) separately, and either
// initialise the map with the result of a function call (possibly using
// Boost.Assign), or write some code somewhere else to populate it.
//
// Or use an array, with lookup code like your C implementation.
std::map<int, std::function<void()>> functors {
{1, [](){std::cout << "A" << std::endl;}},
{2, [](){std::cout << "B" << std::endl;}}
};
int main() {
functors[2]();
}
As noted in the comments, if the real situation is as simple as the example, you could use a function pointer rather than function (and still initialise it with a lambda, if you like), and an array (indexed by id) rather than a map. My example assumes that you want a more general solution, mapping arbitrary values to arbitrary functors.
Simple:
#include <functional>
#include <iostream>
#include <vector>
void sayA() { std::cout << "A" << std::endl; }
void sayB() { std::cout << "B" << std::endl; }
struct Foo
{
explicit Foo(int i) : i_(i) {}
void operator()() const { std::cout << "foo " << i_<< "!" << std::endl; }
int i_;
};
std::vector<std::function<void()>> funcs{ sayA, sayB, Foo(42) };
int main()
{
for (const auto& f : funcs) f();
}

c++ functor and function templates

consider this simple and pointless code.
#include <iostream>
struct A {
template<int N>
void test() {
std::cout << N << std::endl;
}
};
int main() {
A a;
a.test<1>();
}
It is a very simple example of a function template. What if however, I wanted to replace A::test with an overloaded operator() to make it a functor?
#include <iostream>
struct A {
template<int N>
void operator()() {
std::cout << N << std::endl;
}
};
int main() {
A a;
a<1>(); // <-- error, how do I do this?
}
Certainly if the operator() took parameters which were dependent on the template, the compiler could possibly deduce the template. But I just can't figure out the proper syntax to specify template parameters with a parameterless functor.
Is there a proper way to do this?
Obviously, this code would work since it bypasses the functor syntax:
a.operator()<1>();
but that kinda defeats the purpose of it being a functor :-P.
You can only call
a.operator()<1>();
but that would not be using a functor. Functors need a non template operator(), as they must be able to be called as varname() and that won't work with your code.
To make it a real functor change your code a template class (functors are classes):
#include <iostream>
template<int N>
struct A {
void operator()() {
std::cout << N << std::endl;
}
};
int main() {
A<1> a;
a();
}
There's not another "direct" way I know other than the:
a.operator()<1>();
syntax. If you're open to changing the code, moving the template parameter to the class would work, or using a (boost|tr1)::bind to make a (boost|tr1)::function object.
You are trying to pass a template parameter to an instance of an object, which as far as I know is not allowed. You can only pass templates parameters to template functions or template objects.
a.test<1>(); and a.operator()<1>(); work because they are serving as template functions.
Use boost::bind (check out boost libraries) to fix it though.
struct A {
void operator()(int n) {
std::cout << n << std::endl;
}
};
int main(int argc, char* argv[]) {
A a;
boost::function<void()> f = boost::bind<void>(a, 1);
f(); // prints 1
return 0;
}
And you don't even have to mess with templates!
You're stuck. Have you considered something like
struct A {
template<int N>
struct B
{
void operator()()
{ std::cout << N << std::endl; }
};
template<int N>
B<N> functor() {return B<N>();}
};
int main()
{
A a;
a.functor<1>()();
}
Nope, there's no way around it. Like you said, you have to either call the operator explicitly (which defeats the purpose), or the template arguments must be able to be deduced by the compiler.