I am trying to get the second element of the list, but I get an error:
||=== Build: Debug in hellocpp17 (compiler: GNU GCC Compiler) ===|
/home/idf/Documents/c++/hellocpp17/main.cpp||In function ‘int main()’:|
/home/idf/Documents/c++/hellocpp17/main.cpp|67|error: no matching function for call to ‘Get<2>::Get(std::__cxx11::list<unsigned int>&)’|
/home/idf/Documents/c++/hellocpp17/main.cpp|40|note: candidate: constexpr Get<2>::Get()|
/home/idf/Documents/c++/hellocpp17/main.cpp|40|note: candidate expects 0 arguments, 1 provided|
/home/idf/Documents/c++/hellocpp17/main.cpp|40|note: candidate: constexpr Get<2>::Get(const Get<2>&)|
/home/idf/Documents/c++/hellocpp17/main.cpp|40|note: no known conversion for argument 1 from ‘std::__cxx11::list<unsigned int>’ to ‘const Get<2>&’|
/home/idf/Documents/c++/hellocpp17/main.cpp|40|note: candidate: constexpr Get<2>::Get(Get<2>&&)|
/home/idf/Documents/c++/hellocpp17/main.cpp|40|note: no known conversion for argument 1 from ‘std::__cxx11::list<unsigned int>’ to ‘Get<2>&&’|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
Program:
#include <iostream>
#include <algorithm>
#include <list>
using namespace std;
template<unsigned n>
struct Get
{
template<class X, class...Xs>
constexpr auto operator()(X x, Xs...xs)
{
if constexpr(n > sizeof...(xs) )
{
return;
}
else if constexpr(n > 0)
{
return Get<n-1> {}(xs...);
}
else
{
return x;
}
}
};
int main()
{
list<unsigned> l = { 7, 5, 16, 8 };
unsigned l2 = Get<2>(l);
cout << l2 << endl;
return 0;
}
EDIT 1
If I instantiate a Get<2>, this error is reported by the compiler
unsigned l2 = Get<2>()(l);
/home/idf/Documents/c++/hellocpp17/main.cpp|67|error: void value not ignored as it ought to be|
You can try with
unsigned l2 = Get<2>{}(7, 5, 16, 8);
The first problem in your code is that
Get<2>(l);
isn't a call to operator() of Get<2>; it's a construction of a Get<2> object with a std::list parameter.
Unfortunately there isn't a Get<2> constructor that receive a std::list.
The second problem in your code is that if you call the operator() of Get<2> as you think
Get<2>{}(l)
where l is a std::list, you pass a single argument; not a variadic list of arguments. And you can use the list l only run-time, not compile time as you want.
Unfortunately the Get<2>{}(7, 5, 16, 8) way (the operator() that receive a variadic list of arguments) is incompatible with a variable that contain a list.
I mean... you can't do something as follows
auto l = something{7, 5, 16, 8};
Get<2>{}(l);
But, if you modify the operator() to receive a std::integer_sequence as follows
template <template <typename X, X...> class C,
typename T, T I0, T ... Is>
constexpr auto operator() (C<T, I0, Is...> const &)
{
if constexpr (n > sizeof...(Is) )
return;
else if constexpr (n > 0)
return Get<n-1>{}(C<T, Is...>{});
else
return I0;
}
you can pass through a l variable as follows
auto l { std::integer_sequence<int, 7, 5, 16, 8>{} };
unsigned l2 = Get<2>{}(l);
Related
The following code tries to make compile-time decisions based on the last argument passed in a parameter pack. It contains a comparison if the number of parameter-pack arguments is > 0 and then tries to get the last element of it. However, the constructed tuple is accessed at an invalid index which is supposedly bigger than the max tuple index (as the static_assert shows).
How is that possible if I do cnt-1?
Demo
#include <cstdio>
#include <concepts>
#include <utility>
#include <tuple>
template <typename... Args>
auto foo(Args&&... args)
{
auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
constexpr std::size_t cnt = sizeof...(Args);
if constexpr (cnt > 0 && std::same_as<std::remove_cvref_t<std::tuple_element_t<cnt-1, decltype(tuple)>>, int>) {
printf("last is int\n");
} else {
printf("last is not int\n");
}
}
int main()
{
foo(2);
foo();
}
Error:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/tuple: In instantiation of 'struct std::tuple_element<18446744073709551615, std::tuple<> >':
<source>:13:25: required from 'auto foo(Args&& ...) [with Args = {}]'
<source>:24:8: required from here
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/tuple:1357:25: error: static assertion failed: tuple index must be in range
1357 | static_assert(__i < sizeof...(_Types), "tuple index must be in range");
| ~~~~^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/tuple:1357:25: note: the comparison reduces to '(18446744073709551615 < 0)'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/tuple:1359:13: error: no type named 'type' in 'struct std::_Nth_type<18446744073709551615>'
1359 | using type = typename _Nth_type<__i, _Types...>::type;
| ^~~~
Short-circuiting that stops the rhs from being evaluated (having its value computed at runtime) doesn't stop it from being instantiated (having template arguments substituted into templates, checking them for validity, all at compile-time).
I don't see any particular reason why it couldn't work the way you expect, it just wasn't added to the language (yet).
As #wohlstad said, if constexpr is the solution:
if constexpr (cnt > 0)
{
if constexpr (std::same_as<std::remove_cvref_t<std::tuple_element_t<cnt - 1, decltype(tuple)>>, int>)
{
...
The first if must be constexpr, while the second only should (in your scenario).
You can force the compiler to evaluate the 2nd condition only if cnt > 0 using if constexpr (available since c++17) and separating into 2 nested ifs:
#include <cstdio>
#include <concepts>
#include <utility>
#include <tuple>
template <typename... Args>
auto foo(Args&&... args)
{
auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
constexpr std::size_t cnt = sizeof...(Args);
//-----vvvvvvvvv---------
if constexpr (cnt > 0)
{
if (std::same_as<std::remove_cvref_t<std::tuple_element_t<cnt - 1, decltype(tuple)>>, int>) {
printf("last is int\n");
}
else {
printf("last is not int\n");
}
}
}
int main()
{
foo(2);
foo();
}
Output:
last is int
The following program does not compile:
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
test<2, 3, true, false>(2, 1, {8, 8});
}
See it live on Coliru.
The error message
g++ -std=c++17 -O1 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:8:41: error: too many arguments to function 'void test(ParametersType&& ...)
[with unsigned int dim = 2; unsigned int N = 3; bool P = true; bool C = false; ParametersType = {}]'
8 | test<2, 3, true, false>(2, 1, {8, 8});
| ^
main.cpp:2:6: note: declared here
2 | void test(ParametersType&&... par)
| ^~~~
indicates that the parameter pack ParametersType... is deduced to an empty one, while I would expect it to be deduced according to the types of the arguments passed to test.
The problem is in the {8, 8} parameter passed to test.
Explicitly passing a std::array to the function solves the problem:
#include <array>
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
test<2, 3, true, false>(2, 1, std::array<int, 2>{8, 8});
}
See it live on Coliru.
Why does the compiler apparently incorrectly deduces the pack in the first example?
If the compiler is not able to deduce {8, 8} to an std::array, I would expect an "impossible to deduce" error. Why instead does the compiler deduce the pack to an empty one?
Template errors are hard to get right. It's just a quality of implementation. Clang for instances gives
main.cpp:2:6: note: candidate template ignored: substitution failure
[with dim = 2, N = 3, P = true, C = false]: deduced incomplete pack <int, int, (no value)>
for template parameter 'ParametersType'
which is easier to understand. And yes, unless using auto, {stuff} has no type.
From cppreference:
A braced-init-list is not an expression and therefore has no type,
e.g. decltype({1,2}) is ill-formed. Having no type implies that
template type deduction cannot deduce a type that matches a
braced-init-list, so given the declaration template void
f(T); the expression f({1,2,3}) is ill-formed.
You can also use auto in this context to fix your issue:
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
auto x = { 8, 8 };
test<2, 3, true, false>(2, 1, x);
}
When I try to compile this code:
#include <iostream>
#include <limits.h>
// End recursive template-expansion of function select below.
template <typename Type>
static inline constexpr Type select(unsigned index)
{ return Type(); }
// Select one of the items passed to it.
// e.g. select(0, a, b, c) = a; select(1, a, b, c) = b; etc.
template <typename Type, typename... Params>
[[gnu::always_inline]]
static inline constexpr Type select(unsigned index, Type value, Params... values)
{ return index == 0 ? value : select<Type>(index - 1, values...); }
template <typename Type>
[[gnu::always_inline]]
static inline constexpr Type reflect_mask_helper_1(Type mask, Type shift, Type value)
{ return ((value & mask) >> shift) | ((value << shift) & mask); }
template <typename Type>
[[gnu::always_inline]]
static inline constexpr Type reflect_mask_helper_0(unsigned i, Type value)
{
return i == 0
? value
: reflect_mask_helper_0(
i - 1,
reflect_mask_helper_1<Type>(
select(i - 1, 0xaaaaaaaaaaaaaaaa, 0xcccccccccccccccc, 0xf0f0f0f0f0f0f0f0,
0xff00ff00ff00ff00, 0xffff0000ffff0000, 0xffffffff00000000),
1 << (i - 1),
value));
}
template <typename Type>
[[gnu::flatten]]
static inline constexpr Type reflect_mask(Type value)
{ return reflect_mask_helper_0(__builtin_ctz(sizeof(Type) * CHAR_BIT), value); }
int main(void) {
for (int i = 0; i < 65536; i++) {
std::cout << reflect_mask<uint16_t>(i) << std::endl;
}
}
gcc gives me an error saying the function reflect_mask_helper_0 cannot be inlined because it is recursive. However, the function select is also recursive, but gcc inlines it without complaining. What am I missing here?
(I need it to be recursive, since constexpr functions cannot contain loops under C++11.)
Error message:
% g++ test.cpp -O3 -march=native -c
test.cpp: In function ‘constexpr Type reflect_mask_helper_0(unsigned int, Type) [with Type = short unsigned int]’:
test.cpp:23:30: error: inlining failed in call to always_inline ‘constexpr Type reflect_mask_helper_0(unsigned int, Type) [with Type = short unsigned int]’: recursive inlining
23 | static inline constexpr Type reflect_mask_helper_0(unsigned i, Type value)
| ^~~~~~~~~~~~~~~~~~~~~
test.cpp:27:28: note: called from here
27 | : reflect_mask_helper_0(
| ~~~~~~~~~~~~~~~~~~~~~^
28 | i - 1,
| ~~~~~~
29 | reflect_mask_helper_1<Type>(
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 | select(i - 1, 0xaaaaaaaaaaaaaaaa, 0xcccccccccccccccc, 0xf0f0f0f0f0f0f0f0,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31 | 0xff00ff00ff00ff00, 0xffff0000ffff0000, 0xffffffff00000000),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 | 1 << (i - 1),
| ~~~~~~~~~~~~~
33 | value));
| ~~~~~~~
test.cpp: In function ‘int main()’:
test.cpp:23:30: error: inlining failed in call to always_inline ‘constexpr Type reflect_mask_helper_0(unsigned int, Type) [with Type = short unsigned int]’: recursive inlining
23 | static inline constexpr Type reflect_mask_helper_0(unsigned i, Type value)
| ^~~~~~~~~~~~~~~~~~~~~
test.cpp:27:28: note: called from here
27 | : reflect_mask_helper_0(
| ~~~~~~~~~~~~~~~~~~~~~^
28 | i - 1,
| ~~~~~~
29 | reflect_mask_helper_1<Type>(
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 | select(i - 1, 0xaaaaaaaaaaaaaaaa, 0xcccccccccccccccc, 0xf0f0f0f0f0f0f0f0,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31 | 0xff00ff00ff00ff00, 0xffff0000ffff0000, 0xffffffff00000000),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 | 1 << (i - 1),
| ~~~~~~~~~~~~~
33 | value));
| ~~~~~~~
select doesn't actually calls itself. It pops the front of the type list it received and then calls another specialization of select<Type, ...>. The trailing parameter pack is different. Since that "recursion" is essentially a finite set of nested function calls (different functions), GCC can see right through it, regardless of the run-time parameter.
But reflect_mask_helper_0 does call itself, with the same template arguments, indefinitely. GCC has no way to tell how deep this run-time recursion will go at run-time. Recall that a constexpr function is still a regular function that must be invocable at run-time.
If you check out the resulting assembly code, if you remove the always_inline and flatten attributes, you can see that gcc actually inlines everything correctly.
So, this issue is a QoI thing. Maybe, at that point, when always_inline handled, it cannot be inlined (hence the error message), but gcc decides to inline it afterwards anyways.
Btw., you can finetune gcc, and with a little modification to your code, gcc can compile it:
pass --param max-early-inliner-iterations=3 to gcc
remove the flatten attribute (no idea, why it matters...)
(So, actually, this issue has nothing to do with recursive calls - from the compiler standpoint, it doesn't matter whether the function is recursive, or not, it just follows the flow of the code - to a certain extent, of course. Here, recursive depth is just 4, it is not too hard to follow for a compiler)
Here’s the solution I’ve found, thanks to grek40’s comment and to StoryTeller’s answer.
(As for my previous problem with the unused function template instance left in the compiled binary, I solved it by compiling the original code — without the gnu::always_inline and gnu::flatten attributes — with the arguments -ffunction-sections -fdata-sections -Wl,--gc-sections.)
Now reflect_mask_helper_0 is inside a struct (because C++ doesn’t allow partial specialization of function templates), and the i parameter of the function became the Index parameter of the struct template.
#include <iostream>
#include <limits.h>
// End recursive template-expansion of function select below.
template <typename Type>
static inline constexpr Type select(unsigned index)
{ return Type(); }
// Select one of the items passed to it.
// e.g. select(0, a, b, c) = a; select(1, a, b, c) = b; etc.
template <typename Type, typename... Params>
[[gnu::always_inline]]
static inline constexpr Type select(unsigned index, Type value, Params... values)
{ return index == 0 ? value : select<Type>(index - 1, values...); }
template <typename Type>
[[gnu::always_inline]]
static inline constexpr Type reflect_mask_helper_1(Type mask, Type shift, Type value)
{ return ((value & mask) >> shift) | ((value << shift) & mask); }
template <typename Type, unsigned Index>
struct reflect_mask_helper_0
{
[[gnu::always_inline]]
static inline constexpr Type invoke(Type value)
{
return reflect_mask_helper_0<Type, Index - 1>::call(
reflect_mask_helper_1<Type>(
static_cast<Type>(select(Index - 1,
0xaaaaaaaaaaaaaaaa, 0xcccccccccccccccc, 0xf0f0f0f0f0f0f0f0,
0xff00ff00ff00ff00, 0xffff0000ffff0000, 0xffffffff00000000)),
1 << (Index - 1),
value));
}
};
template <typename Type>
struct reflect_mask_helper_0<Type, 0>
{
[[gnu::always_inline]]
static inline constexpr Type invoke(Type value) { return value; }
};
template <typename Type>
static inline constexpr Type reflect_mask(Type value)
{ return reflect_mask_helper_0<Type, __builtin_ctz(sizeof(Type) * CHAR_BIT)>::invoke(value); }
int main(void) {
for (int i = 0; i < 65536; i++) {
std::cout << reflect_mask<uint16_t>(i) << std::endl;
}
}
I have written a generic exponential backoff retry loop in C++11. I'm using std::function to pass the callable to retry loop. callable will be retried if isRetriable function returns true.
#include <algorithm>
#include <cassert>
#include <chrono>
#include <functional>
#include <iostream>
#include <thread>
constexpr int64_t max_backoff_milliseconds = 30000; // 30 seconds
template <class R, class... Args>
R Retry(int max_retry_count, int64_t initial_dealy_milliseconds,
const std::function<bool(R)> &isRetriable,
const std::function<R(Args...)> &callable, Args &&... args)
{
int retry_count = 0;
while (true) {
auto status = callable(std::forward<Args>(args)...);
if (!IsRetriable(status)) {
return status;
}
if (retry_count >= max_retry_count) {
// Return status and abort retry
return status;
}
int64_t delay_milliseconds = 0;
if (initial_dealy_milliseconds > 0) {
delay_milliseconds =
std::min(initial_dealy_milliseconds << retry_count,
max_backoff_milliseconds);
}
std::cout << "Callable execution failed. Retry Count:"
<< retry_count + 1 << std::endl;
std::this_thread::sleep_for(
std::chrono::milliseconds(delay_milliseconds));
retry_count++;
}
}
bool isRetriable(int status) {
if (status == 5)
return true;
return false;
}
int foo(int x, int y) {
static int a = 1;
a += (x + y);
return a / 6;
}
int main() {
auto result = Retry(1000, 100, isRetriable, foo, 1, 3);
std::cout << result << std::endl;
return 0;
}
When I compile it, I'm getting below error:
prog.cpp: In function ‘int main()’:
prog.cpp:50:71: error: no matching function for call to ‘Retry(int,
int, bool (&)(int), int (&)(int, int), int, int)’
auto result = Retry<int, int, int>(1000, 100, isRetriable, foo, 1, 3);
^
prog.cpp:11:3: note: candidate: template<class R, class ... Args> R
Retry(int, int64_t, const std::function<bool(R)>&, const
std::function<_Res(_ArgTypes ...)>&, Args&& ...)
R Retry(int max_retry_count,
^~~~~
prog.cpp:11:3: note: template argument deduction/substitution failed:
prog.cpp:50:71: note: mismatched types ‘const
std::function<int(_ArgTypes ...)>’ and ‘int(int, int)’
auto result = Retry<int, int, int>(1000, 100, isRetriable, foo, 1, 3);
^
Could someone explain to me why I have this error?
I'm sure there's a good duplicate for this but...
Here's a shorter reproduction:
template <typename T> void foo(std::function<bool(T)> ) { }
bool maybe(int ) { return false; }
foo(maybe); // error: no matching function call to 'foo(bool (&)(int))'
You may ask - what?! maybe is something that's callable with some T that returns bool. But that's not how template deduction works. In order to deduce std::function<bool(T)> against an argument, that argument needs to be a std::function. maybe isn't a std::function, it's just a function, so that deduction fails. Any kind of deduction with a different kind of expression will also fail:
foo([](int ) { return true; }); // also error
Basically, trying to deduce a std::function is almost always the wrong thing to do. First, it's wrong because it won't work. Second, it's wrong because even if it did work, you're incurring type erasure in a context in which you probably don't need it.
What you want to do instead is deduce arbitrary callables, and then determine what these other arguments are based on those callables. The return type of callable is just what you get when you call callable with Args..., and you want to ensure that isRetriable is a predicate on that type.
One approach to that is:
template <typename Predicate, typename Callable, typename... Args,
// figure out what the callable returns
typename R = std::decay_t<std::invoke_result_t<Callable&, Args...>>,
// require that Predicate is actually a Predicate
std::enable_if_t<
std::is_convertible_v<std::invoke_result_t<Predicate&, R>, bool>,
int> = 0>
R Retry(int max_retry_count, int64_t initial_dealy_milliseconds,
Predicate&& isRetriable,
Callable&& callable,
Args&&... args)
{
// ....
}
Bar holds a std::vector of std::pairs of std::arrays of FooValueAdaptors.
FooValueAdaptor implicitly converts int to bool to FooValue, which makes little sense in this contrived example, but perfect sense in my application.
I implemented a convenience function Bar::addEntries for adding multiple entries at once, but calling it with more than two arguments fails to compile using GCC 4.8.0. See the error messages below.
#include <array>
#include <utility>
#include <vector>
enum class FooValue {
A,
B,
C
};
class FooValueAdaptor {
public:
FooValueAdaptor(bool value)
: m_value(static_cast<FooValue>(value)) {
}
FooValueAdaptor(int value)
: m_value(static_cast<FooValue>(static_cast<bool>(value))) {
}
FooValueAdaptor(FooValue value)
: m_value(value) {
}
operator FooValue() {
return m_value;
}
operator bool() {
return m_value == FooValue::C;
}
private:
FooValue m_value;
};
template<std::size_t nFirst, std::size_t nSecond>
class Bar {
public:
typedef std::array<FooValueAdaptor, nFirst> First;
typedef std::array<FooValueAdaptor, nSecond> Second;
typedef std::pair<First, Second> Entry;
Bar()
: m_table() {
}
void addEntry(First first, Second second) {
m_table.push_back(std::make_pair(first, second));
}
template <typename... Args>
void addEntries() {
}
template <typename... Args>
void addEntries(First first, Second second, Args... args) {
addEntry(first, second);
addEntries(args...);
}
private:
std::vector<Entry> m_table;
};
int main(int argc, char **argv) {
Bar<2, 1> b;
b.addEntry({ 0, 0 }, { 0 });
b.addEntries(
{ 0, 1 }, { 0 },
{ 1, 0 }, { 0 },
{ 1, 1 }, { 1 }
);
return 0;
}
Compiler error messages:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:74:2: error: no matching function for call to ‘Bar<2ul, 1ul>::addEntries(<brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>)’
);
^
test.cpp:74:2: note: candidates are:
test.cpp:53:7: note: template<class ... Args> void Bar<nFirst, nSecond>::addEntries() [with Args = {Args ...}; long unsigned int nFirst = 2ul; long unsigned int nSecond = 1ul]
void addEntries() {
^
test.cpp:53:7: note: template argument deduction/substitution failed:
test.cpp:74:2: note: candidate expects 0 arguments, 6 provided
);
^
test.cpp:57:7: note: void Bar<nFirst, nSecond>::addEntries(Bar<nFirst, nSecond>::First, Bar<nFirst, nSecond>::Second, Args ...) [with Args = {}; long unsigned int nFirst = 2ul; long unsigned int nSecond = 1ul; Bar<nFirst, nSecond>::First = std::array<FooValueAdaptor, 2ul>; Bar<nFirst, nSecond>::Second = std::array<FooValueAdaptor, 1ul>]
void addEntries(First first, Second second, Args... args) {
^
test.cpp:57:7: note: candidate expects 2 arguments, 6 provided
How can I help the compiler's deduction along?
You need to tell the compiler explicitly what you need:
void addEntries(std::initializer_list<std::pair<First, Second>> il) {
for( const auto& e : il ) {
addEntry(e.first,e.second);
}
}
and call it like this:
b.addEntry({{ 0, 0 }}, {{ 0 }});
b.addEntries({
{{{ 0, 1 }}, {{ 0 }}},
{{{ 1, 0 }}, {{ 0 }}},
{{{ 1, 1 }}, {{ 1 }}}
});
Notice the huge amount of curly brackets, but I think the above is actually the only correct syntax. Fewer brackets are accepted by both GCC 4.8 and Clang 3.2, but Clang gives lots of warnings, the above fixes that. Some people are already working on a "fix", but that'll take some time.