I'm trying to supply a parameter pack to initialize an array. I think it should work because:
I'm using sizeof... to get the size of the parameter pack
It's a template, and sizeof is a compile-time construct, so it should be known at compile-time, which means arr should not be a variable length array
I'm forwarding the arguments correctly
Yet I get garbage as output and a warning. First the code:
#include <iostream>
#include <utility>
template <typename... Args>
void foo(Args&&... args)
{
int arr[sizeof...(Args)]{std::forward<Args>(args)()...};
for (auto i = 0u; i < sizeof(arr); ++i)
std::cout << arr[i];
}
int a() { return 1; }
int b() { return 2; }
int c() { return 3; }
int main()
{
foo(a, b, c);
}
Then the warning and output:
warning: iteration 3 invokes undefined behavior [-Waggressive-loop-optimizations]
std::cout << arr[i];
~~~~~~~~~~^~~~~~~
note: within this loop
for (auto i = 0u; i < sizeof(arr); ++i)
~~^~~~~~~~~
1230-282327744327670000-133971368332712
Can anyone see my mistake?
template <typename... Args>
void foo(Args&&... args)
{
// edit 1 : define the extent of the array once, reuse.
constexpr std::size_t extent = sizeof...(Args);
// edit 2 : in this case, no need to forward references since
// we're not actually forwarding them anywhere
int arr[extent]{args()...};
// edit 3 : 0 < i < extent of array
for (std::size_t i = 0; i < extent ; ++i)
std::cout << arr[i];
}
As mentioned in the comments by #Casey, sizeof(arr) returns the size of a variable of the type you chose for your array multiplied for the length of the array itself (in your case, 3 * sizeof(int)).
To solve it, you can either iterate over sizeof...(Args) using this:
for (auto i = 0u; i < sizeof...(Args); ++i)
Or print the values while you fill the array, as it follows:
#include <iostream>
#include <utility>
template <typename... Args>
void foo(Args&&... args) {
int arr[sizeof...(Args)] = {
(std::cout << args(), std::forward<Args>(args)())...
};
(void)arr;
}
int a() { return 1; }
int b() { return 2; }
int c() { return 3; }
int main() {
foo(a, b, c);
}
If the sole purpose of the function is to print the values, you can also use this:
int arr[sizeof...(Args)] = { (std::cout << args(), 0)... };
Note that the code above does not consider the case of sizeof...(Args) equal to 0.
It's quite trivial indeed to do that and I'd left it out of the answer.
Related
All try to do is to make this piece of code
int main() {
if constexpr( ??? ) {
std::cout << "Yes\n";
std::cout << f() << '\n';
std::cout << f(42) << '\n';
}
else {
std::cout << "No\n";
}
return 0;
}
compile if the function f is defined as in any of these examples
// Example 1
int f(int n = 0) { return n; }
// Example 2
int f(int n) { return n; }
int f() { return 0; }
// Example 3
int f(int n) { return n; }
and display Yes for examples 1 and 2, and display No for the example 3.
Is this even possible? I think I've seen someone doing this with SFINAE but I don't remember how exactly it was done and where exactly I saw that. Thank you in advance.
if constexpr can’t protect ill-formed code outside of any template (e.g., in main). The obvious thing to do is to write a template that accepts f itself as a template argument, but to do that you have to reify your overload set. The usual way to do that is as a SFINAE-friendly function object:
template<class F,class=void>
constexpr bool opt=false;
template<class F>
constexpr bool opt<F,decltype(std::declval<F>()(1),void(std::declval<F>()()))> =true;
template<class F> int use(F &&x) {
if constexpr(opt<F>) return x(1)+x();
else return 0;
}
const auto f_=[](auto &&...aa) -> decltype(f(std::forward<decltype(aa)>(aa)...))
{return f(std::forward<decltype(aa)>(aa)...);};
int main() {use(f_);}
In some cases there is also the option of creating a “fake” template that uses calls that are formally dependent but always use the types you want, but that’s impossible for a call f() with no arguments, which is ill-formed (possibly with no diagnostic required) immediately if your f requires an argument since it can’t depend on a template parameter.
With std::array you can do
std::array<int,3> v = {1,2,3};
But I want to provide a wrapper
template <typename T, int n> circular_array {
auto operator[](size_t i){
return m_data[i%n];
}
// TODO forward all other methods directly except ``at`` which we don't need
private:
std::array<t,n> m_data;
}
but I lose the aggregate initialization that I had above for std::array. This will not work.
circular_array<int,3> v = {1,2,3};
though if I made m_data public I could do
circular_array<int,3> v = {{1,2,3}};
which is not desired.
Is there a way to achieve circular_array as a drop in for std::array including aggregate initialization?
Not sure if it's exactly what you're looking for, but you can use inheritance (that is derive your class from std::array) rather than composition (i.e. having a std:array data member).
Here's a demo:
#include <array>
#include <iostream>
template <typename T, int n>
class circular_array : public std::array<T, n>
{
public:
auto operator[](size_t i) {
return std::array<T, n>::data()[i % n];
}
};
int main()
{
circular_array<int, 3> v = {1,2,3};
for (size_t i = 0; i < 10; ++i) {
std::cout << v[i] << std::endl;
}
return 0;
}
I have tested this code in Visual Studio (Windows) and it works as expected; the native MSVC compiler gives no diagnostic (even in code analysis mode) but clang-cl issues the following for the aggregate initialization (which it doesn't give when using such syntax for a native std:array object):
warning : suggest braces around initialization of subobject
[-Wmissing-braces]
Not being a Language-Lawyer, I'm not sure if this means that the circular_array<int, 3> v = {1,2,3}; line is truly still aggregate initialization; but, if it's not, then I'm equally unsure what it is.
The solution is to realize that std::array has to pull off the same trick. It does this by making it's single member public rather than hiding it.
So the (partial) solution is
#include <array>
#include <iostream>
template <typename T, int n>
class circular_array
{
private:
static
constexpr int Wrap(int kX) noexcept
{
if (kX < 0)
kX += n * (-kX / n + 1);
return kX % n;
}
public:
typename std::array<T,n>::reference operator[](int i) {
return m_data[Wrap(i)];
}
std::array<T,n> m_data;
};
int main()
{
circular_array<int, 3> v = {1,2,3};
std::cout << v[-3] << std::endl;
std::cout << v[-2] << std::endl;
std::cout << v[-1] << std::endl;
std::cout << v[0] << std::endl;
std::cout << v[1] << std::endl;
std::cout << v[2] << std::endl;
std::cout << v[3] << std::endl;
return 0;
}
which outputs
1
2
3
1
2
3
1
which works all the way down to c++11 as far as I have tested. I still have to implement all the other forwarding calls but the principle is clear though kludgy.
https://godbolt.org/z/Kqhsa8cP5
Question:
If you want, for example, a variadic function that takes arbitrary number of parameter Args&&...args, and prints all those arguments t times. What's more is that you want t to be defaulted to 1, so it prints all args one time by default.
The first thing you would try is:
template <typename ... Args>
void foo(Args... args, unsigned t = 1) {
for (unsigned i = 0; i < t; ++i) {
(std::cout << ... << args);
}
}
Apparently this doesn't work unless you explicitly pass in the template parameters:
// Error: expected 1 argument, got 2
foo(0, "Hello, world!");
Because default parameters are treated as normal parameters while template deduction, and the parameter pack would always be empty. This prevents you from making the function useful. (Related question)
I then decided to use aggregate initialization (especially designated initializer since c++ 20) to simulate a more powerful "default parameter". It looks like this:
struct foo_t {
unsigned t = 1;
template <typename ... Args>
void operator() (Args... args) {
for (unsigned i = 0; i < t; ++i) {
(std::cout << ... << args);
}
}
};
int main() {
foo_t{}("Hello, ", "World!\n"); // prints 1 line
foo_t{ 5 }(0, "Hello, world!\n"); // prints 5 lines
return 0;
}
Moreover, this may solve people's complaint that they cannot "skip" default function parameters, with the help of c++ 20 designated intializers:
struct bar_t {
const std::string& str = "Hello, world!";
int t = 1;
void operator() () {
for (int i = 0; i < t; ++i) {
std::cout << str << std::endl;
}
}
};
int main() {
// Skips .str, using the default "Hello, World!"
bar_t{ .t = 10 }();
return 0;
}
I am wondering whether there are any potential pitfalls to do this.
Background (Can be safely ignored)
So yesterday I was wandering around SO and encountered a question (but it was later deleted) that asked about how to combine default std::source_location parameter with variadic template:
template<typename... Args>
void log(Args&&... args, const std::experimental::source_location& location = std::experimental::source_location::current()) {
std::cout << location.line() << std::endl;
}
Apparently this does not work as expected, just as stated in the question. So I came up with the following code:
struct logger {
const std::experimental::source_location& location = std::experimental::source_location::current();
template <typename... Args>
void operator() (Args&&... args) {
std::cout << location.line() << std::endl;
}
};
int main(int argc, char** argv) {
logger{}("I passed", argc, "arguments.");
return 0;
}
But found out it can do more, thus this question.
There is at least one pitfall with lifetime (extension):
const std::string& str = "Hello, world!"; create dangling pointer, (No lifetime extension for member).
Following is fine:
void repeat_print(const std::string& str = "Hello, world!", int t = 1) {/*..*/}
int main()
{
repeat_print();
}
but following is not:
struct bar_t {
const std::string& str = "Hello, world!";
int t = 1;
void operator() () const { /*..*/ }
};
int main()
{
bar_t{}();
}
You might fix bar_t to take member by value, but then you would do extra copy in some cases.
I can't able to understand , so please help me .
Whrn we are passing the array to any function and then we write the array type in function parameter to fetch it but why we are not initialize its size in the parameter .
Of course you could specify (fixed) size of array as function parameter - you have to pass array by reference.
void func(int (&x)[100]);
is passing array of int with size 100.
You could even make a template for it
template<class T, size_t N> void func(T (&x)[N]) {...}
In C++, always prefer containers to raw pointers or arrays when possible.
Array types in function signatures are actually pointers. The following three declarations are all exactly the same:
void foo(int a[10]);
void foo(int a[]);
void foo(int* a);
In all three cases, foo takes a single parameter: a pointer to an int. When you pass an array to that function, it implicitly decays to a pointer to its first element.
When an array decays into a pointer, the length of the array is lost. That means the following code will compile, but is logically wrong:
void foo(int a[10]) {
for (size_t i = 0; i < 10; ++i) {
std::cout << a[i] << '\n';
}
}
int main() {
// Whoops, wrong size array!
int arr[5] = {};
foo(arr);
}
Live Demo
The length declaration, in this case, is a complete and total lie. Writing a meaningless number in the function definition just increases the risk someone will make an error.
If you must use raw pointers for a function parameter accepting an array, your function should also accept a size parameter:
void foo(int* a, size_t length) {
for (size_t i = 0; i < length; ++i) {
std::cout << a[i] << '\n';
}
}
int main() {
int arr[5] = {};
foo(arr, 5);
}
Live Demo
This is also dangerous though, since it's entirely possible for someone to pass the wrong size and cause errors:
void foo(int* a, size_t length) {
for (size_t i = 0; i < length; ++i) {
std::cout << a[i] << '\n';
}
}
int main() {
int arr[5] = {};
//Whoops, passed the wrong size!
foo(arr, 10);
}
Live Demo
For that reason, you should prefer to use a container:
void foo(const std::vector<int>& a) {
for (int i : a) {
std::cout << i << '\n';
}
}
int main() {
std::vector<int> arr(5);
foo(arr);
}
Live Demo
If you don't know what type of container to use; default to std::vector. If your function must support multiple types of containers, use a template:
template <typename Container>
void foo(const Container& a) {
for (int i : a) {
std::cout << i << '\n';
}
}
int main() {
std::vector<int> arr(5);
foo(arr);
std::array<int, 5> arr2 = {};
foo(arr2);
}
Live Demo
I have some generic function, which looks similar to
template<int P>
struct foo {
static const int value = ...;
};
Now, I want to call this generic function in a loop. Like so:
for (int i = 0; i < 100; ++i)
{
auto bar = foo<i>::value;
}
But I get a lot of error messages. Like
the value of 'i' is not used in a constant expression
int i is not constant
I tried to fix it with:
foo<(const int)i>::value;
But to no avail. So, what is wrong with that and how can I make it work?
You cannot do it this way.
for (int i = 0; i < 100; ++i)
{
auto bar = foo<i>::value;
}
i needs to me a constant expression, so that the compiler can generate the code for it when it compiles your program.
Here's an exhaustive explanation of what constant expressions are:
http://en.cppreference.com/w/cpp/language/constant_expression
Here's a segment from the site:
int n = 1;
std::array<int, n> a1; // error: n is not a constant expression
const int cn = 2;
std::array<int, cn> a2; // OK: cn is a constant expression
So to make it happen compile time, you need to make your loop into a template recursion using variadic templates.
Maybe you can understand what you need to do better if you read this example:
// Example program
#include <iostream>
#include <string>
template<int P>
struct foo
{
static const int value = P;
};
template <int TIndex>
int call()
{
return foo<TIndex>::value;
}
template <int TIndex, int TIndex2, int ...Rest>
int call ()
{
return call<TIndex>() + call<TIndex2, Rest...>();
}
int main()
{
std::cout << "Test: " << call<1, 2>() << "\n"; // prints "Test: 3"
}
Nicky C posted a link to another question. It has a good answer and I don't feel right in copying it here. Take a look at my working example above and then look at the answer here:
https://stackoverflow.com/a/11081785/493298
You should be able to make it work. It's a bit of a syntax hell, but you can manage it, I'm sure.