Passing variable length argument to function C++ - c++

I am trying to create a function that accepts variable number of arguments. But I am getting error in expression decltype(std::initializer_list::size_type) res1=0; as error: expected primary-expression before 'decltype'. The purpose is to declare appropriate variable type that can hold sum of the list (although this declaration will create big enough variable to hold all elements of the list only and not their sum). How can I do this?
Also, how can I make appropriate function return type to return res1 instead of void?
#include <iostream>
#include <initializer_list>
void sum1(std::initializer_list<int> lst1)
{
decltype(std::initializer_list::size_type) res1=0;
for(auto v1:lst1)
{
res1 += v1;
}
std::cout<<" sum = \n"<<res1;
}
int main()
{
sum1({1,2,3,4,5,6,7,8,9,10});
//auto b = sum1({1,2,3,4,5,6,7,8,9,10});
return 0;
}

size_type is not needed for anything in your function. The initializer_list has type int, therefore res1 should be an int and your return type should be int. If you really want to derive the value type from the initializer_list then do so like this:
#include <iostream>
#include <initializer_list>
auto sum1(std::initializer_list<int> lst1)
{
typename std::initializer_list<int>::value_type res1 = 0;
for(auto v1:lst1)
{
res1 += v1;
}
return res1;
}
int main()
{
sum1({1,2,3,4,5,6,7,8,9,10});
auto b = sum1({1,2,3,4,5,6,7,8,9,10});
std::cout << b << std::endl;
return 0;
}
If you want the function to be generic, in which case it is necessary to derive the value type, then the template function looks like this.
#include <iostream>
#include <initializer_list>
template<typename T>
auto sum1(std::initializer_list<T> lst1)
{
typename std::initializer_list<T>::value_type res1 = 0;
for(auto v1:lst1)
{
res1 += v1;
}
return res1;
}
int main()
{
sum1({1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.10});
auto b = sum1({1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.10});
std::cout << b << std::endl;
return 0;
}

Following is corrected code.
#include <iostream>
#include <initializer_list>
int sum1(std::initializer_list<int> lst1)
{
int res1=0;
for(auto v1:lst1)
{
res1 += v1;
}
return res1;
}
int main()
{
std::cout<<" sum = "<<sum1({1,2,3,4,5,6,7,8,9,10});
//auto b = sum1({1,2,3,4,5,6,7,8,9,10});
return 0;
}
You can see working here.
Note: You can change the type of res0 to long or other type if result is not in the limits of int. Also, Change the return type of function sum1 accordingly.

Related

Get type contained in variant at run time in C++?

In C++, how do I print the type contained in a variant at run time?
My use case: passing a dictionary of values from Python to C++ using pybind11, and I want to print out the types that are received.
You can get a generic solution with std::visit and some typename printing library, such as Boost.TypeIndex. An exemplary solution:
#include <iostream>
#include <type_traits>
#include <variant>
#include <boost/type_index.hpp>
int main()
{
std::variant<char, bool, int, double> v;
auto print_variant_type =
[](auto&& value)
{
using T = std::decay_t<decltype(value)>;
std::cout << boost::typeindex::type_id<T>().pretty_name() << std::endl;
};
v = 'a';
std::visit(print_variant_type, v); // prints out "char"
v = true;
std::visit(print_variant_type, v); // prints out "bool"
v = 1;
std::visit(print_variant_type, v); // prints out "int"
v = 1.0;
std::visit(print_variant_type, v); // prints out "double"
}
Live demo: https://godbolt.org/z/Web5zeGof
The only drawback is that it can print "ugly" type names for library types that are type aliases (such as std::string). An alternative for a particular variant instance, possibly more suitable for you, may be using a mapping from a variant index to type names:
using variant_type = std::variant<char, bool, int, double, std::string>;
static const std::array variant_type_names =
{ "char", "bool", "int", "double", "std::string" };
void print_variant_type(const variant_type& v)
{
assert(v.index() < variant_type_names.size());
std::cout << variant_type_names[v.index()] << std::endl;
}
int main()
{
variant_type v;
v = 'a';
print_variant_type(v); // prints out "char"
v = true;
print_variant_type(v); // prints out "bool"
v = 1;
print_variant_type(v); // prints out "int"
v = 1.0;
print_variant_type(v); // prints out "double"
v = std::string("some string");
print_variant_type(v); // prints out "std::string"
}
Live demo: https://godbolt.org/z/9na1qzEKs
You could use function overloading like so:
#include <iostream>
#include <variant>
using VariantT = std::variant<int, float>;
namespace {
std::string name(const float& ) {
return "float";
}
std::string name(const int& ) {
return "int";
}
std::string variantName(const VariantT& v) {
return std::visit(
[](const auto &v) { return name(v); },
v
);
}
}
int main() {
std::variant<int, float> v;
v = 1;
std::cout << variantName(v) << std::endl;
v = 1.f;
std::cout << variantName(v) << std::endl;
}
Tested under MSVC 2022 and C++17. Should work on gcc and clang but untested.
#include <string>
#include <variant>
#include <type_traits>
/**
* \brief Variant type to string.
* \tparam T Variant type.
* \param v Variant.
* \return Variant type as a string.
*/
template<typename T>
std::string variant_type_string(T v)
{
std::string result;
if constexpr(std::is_constructible_v<T, int>) { // Avoids compile error if variant does not contain this type.
if (std::holds_alternative<int>(v)) { // Runtime check of type that variant holds.
result = "int";
}
}
else if constexpr(std::is_constructible_v<T, std::string>) {
if (std::holds_alternative<std::string>(v)) {
result = "string";
}
}
else if constexpr(std::is_constructible_v<T, bool>) {
if (std::holds_alternative<bool>(v)) {
result = "bool";
}
}
else {
result = "?";
}
return result;
}
To use:
std::variant<int, std::string> v { 42 };
std::cout << variant_type_string(v);
// Prints: int

passing nonconstatnt value to template in c++

Question : I need a method to use x variable as input for xSet() methods. Currently the compiler is giving an error saying that
the value of 'x' is not usable in a constant expression
I know what it means. But i want to know if there is any method by which i can pass x value to xSet method.
Thank You !!!
template <int t_ID>
static size_t xSet()
{
return t_ID;
}
int main()
{
for (int x = 0; x <14 ; x++)
{
xSet<x>();
}
return 0;
}
I think what you're trying to do is call a specialisation of a template function by selecting it with a runtime integer?
In which case, you need something like this:
#include <cstddef>
#include <array>
#include <iostream>
#include <utility>
template <int t_ID>
static std::size_t xSet()
{
return t_ID;
}
template<int...Is>
constexpr auto make_xSet_calls(std::integer_sequence<int, Is...>)
{
using function_sig = std::size_t (*)();
return std::array<function_sig, sizeof...(Is)>
{{
&xSet<Is>...
}};
};
int main()
{
auto constexpr limit = 14;
for (int x = 0; x < limit ; x++)
{
std::cout << make_xSet_calls(std::make_integer_sequence<int, limit>())[x]() << '\n';
}
return 0;
}

Cannot use .begin() or .end() on an array

The error reads:
request for member 'begin', 'end' in 'arr' which is non class type int[5],
unable to deduce from expression error.
My code:
#include <iostream>
using namespace std;
int main()
{
int * mypointer;
int arr[5] = {1,3,5,7,9};
mypointer = arr;
for(auto it = arr.begin(); it != arr.end(); ++it) {
cout<<*mypointer<<endl;
mypointer++;
}
return 0;
}
Arrays have no member functions as they aren't a class type. This is what the error is saying.
You can use std::begin(arr) and std::end(arr) from the <iterator> header instead. This also works with types that do have .begin() and .end() members, via overloading:
#include <array>
#include <vector>
#include <iterator>
int main()
{
int c_array[5] = {};
std::array<int, 5> cpp_array = {};
std::vector<int> cpp_dynarray(5);
auto c_array_begin = std::begin(c_array); // = c_array + 0
auto c_array_end = std::end(c_array); // = c_array + 5
auto cpp_array_begin = std::begin(cpp_array); // = cpp_array.begin()
auto cpp_array_end = std::end(cpp_array); // = cpp_array.end()
auto cpp_dynarray_begin = std::begin(cpp_dynarray); // = cpp_dynarray.begin()
auto cpp_dynarray_end = std::end(cpp_dynarray); // = cpp_dynarray.end()
}
For a standard fixed-length C array, you can just write
int c_array[] = {1,3,5,7,9}, acc = 0;
for (auto it : c_array) {
acc += it;
}
The compiler does the behind-the-scenes work, eliminating the need to create all those begin and end iterators.
In C++, arrays are not classes and therefore do not have any member methods. They do behave like pointers in some contexts. You can take advantage of this by modifying your code:
#include <iostream>
using namespace std;
int main()
{
int * mypointer;
const int SIZE = 5;
int arr[SIZE] = {1,3,5,7,9};
mypointer = arr;
for(auto it = arr; it != arr + SIZE; ++it) {
cout<<*mypointer<<endl;
mypointer++;
}
return 0;
}
Of course, this means that mypointer and it both contain the same address, so you don't need both of them.
One thing I'd like to point out for you is that you really don't have to maintain a separate int* to use in dereferencing the array elements, apart from the whole member thing others have well pointed out.
Using a more modern approach, the code is both more readable, as well as safer:
#include <iostream>
#include <algorithm>
#include <array>
#include <iterator>
using namespace std;
int main()
{
std::array<int, 5> cpp_array{1,3,5,7,9};
// Simple walk the container elements.
for( auto elem : cpp_array )
cout << elem << endl;
// Arbitrary element processing on the container.
std::for_each( begin(cpp_array), end(cpp_array), [](int& elem) {
elem *= 2; // double the element.
cout << elem << endl;
});
}
Using the lambda in the second example allows you to conveniently perform arbitrary processing on the elements, if needed. In this example, I'm just showing doubling each element, but you can do something more meaningful within the lambda body instead.
Hope this makes sense and helps.
Perhaps here is a cleaner way to do it using templates and lambdas in c++14:
Define:
template<typename Iterator, typename Funct>
void my_assign_to_each(Iterator start, Iterator stop, Funct f) {
while (start != stop) {
*start = f();
++start;
}
}
template<typename Iterator, typename Funct>
void my_read_from_each(Iterator start, Iterator stop, Funct f) {
while (start != stop) {
f(*start);
++start;
}
}
And then in main:
int x[10];
srand(time(0));
my_assign_to_each(x, x+10, [] () -> int { int rn{}; rn = rand(); return rn; });
my_read_from_each(x, x+10, [] (int value) { std::cout << value << std::endl; });
int common_value{18};
my_assign_to_each(x, x+10, [&common_value] () -> int { return common_value; });
my_read_from_each(x, x+10, [] (int value) { std::cout << value << std::endl; });
Quite late but I think it's worth to mention that:
void findavgTime(int n)
{
int wt1[n];
fill_wt(wt1,n); //Any method that puts the elements into wt1
int wt2[3];
int sum = accumulate(begin(wt1), end(wt1), 0); // Fails but wt2[3] will pass. Reason: variable-sized array type ‘int [n]’ is not a valid template argument)
}

c++ find_if lambda

What is wrong with the code below? It is supposed to find an element in the list of structs if the first of the struct's members equals to 0. The compiler complains about the lambda argument not being of type predicate.
#include <iostream>
#include <stdint.h>
#include <fstream>
#include <list>
#include <algorithm>
struct S
{
int S1;
int S2;
};
using namespace std;
int main()
{
list<S> l;
S s1;
s1.S1 = 0;
s1.S2 = 0;
S s2;
s2.S1 = 1;
s2.S2 = 1;
l.push_back(s2);
l.push_back(s1);
list<S>::iterator it = find_if(l.begin(), l.end(), [] (S s) { return s.S1 == 0; } );
}
Code works fine on VS2012, just one recommendation, pass object by reference instead of pass by value:
list<S>::iterator it = find_if(l.begin(), l.end(), [] (const S& s) { return s.S1 == 0; } );

C++ and currying

I've the code:
#include <iostream>
using namespace std;
auto fn = ([](int x){
return [x](int y) {
return x * y;
};
});
int main() {
int i = fn(2)(4); // 8
cout << i << endl;
return 0;
}
This code works fine.
However, I want to call a second function later like:
auto i = fn(2);
i(4); //error: 'i' cannot be used as a function
Are there any way to call the last function later and then bind with the first call?
The following works as expected
#include <iostream>
using namespace std;
auto fn = [](int x){
return [x](int y) {
return x * y;
};
};
int main() {
auto i = fn(2)(4); // 8
cout << i << endl;
auto j = fn(2);
cout << j(4) << endl;
return 0;
}
ADD
By the way gcc 4.5 with -std=c++0x gives the following error if you use int instead of auto:
currying.cpp:17:17: error: cannot convert ‘<lambda(int)>::<lambda(int)>’ to ‘int’ in initialization
currying.cpp:19:16: error: ‘j’ cannot be used as a function
which is an "obvious" and useful information to get what's going wrong.
The result of fn is not an integer, so you cannot assign fn(2) to an integer (don't even know why that compiles).
You should be able to do auto i = fn(2);
This works for me:
int main() {
auto i = fn(2);
cout << i(4) << endl; // prints 8
return 0;
}