I am trying to pass a more "generic" const input parameter to a constexpr implementation for fibonacci. When I replace the template parameter with an int, things are hunky-dory again.
#include<iostream>
template <typename T>
constexpr auto fib_ce(T n) {
return (n>1) ? fib_ce(n-1)+fib_ce(n-2) : 1;
}
int main() {
std::cout<<fib_ce(4)<<"\n";
}
This is the error I get:
g++ -std=c++14 -o constexpr_fib constexpr_fib.cpp
constexpr_fib.cpp:4:19: fatal error: recursive template instantiation exceeded maximum depth of 256
return (n>1) ? fib_ce(n-1)+fib_ce(n-2) : 1;
^
How do I provide a template argument to a constexpr, that can take inputs like long, int, unsigned long, etc etc for this constexpr
The rule in [dcl.spec.auto] is:
If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression,
the program is ill-formed.
This is to just cut short the arbitrary complexity that could be infinite recursive deduction. Fear not though, there are ways around this problem:
Just use T instead of auto:
template <class T>
constexpr T fib_ce(T n) {
return (n>1) ? fib_ce(n-1)+fib_ce(n-2) : 1;
}
We also have the rule:
Once a non-discarded return statement has been seen in a function, however, the return type deduced from that statement can be used in the rest of the function, including in other return
statements.
So we can use an if statement instead of the conditional operator. We just have to invert the logic so that the return statement with known type goes first:
template <typename T>
constexpr auto fib_ce(T n) {
if (n <= 1) {
return static_cast<T>(1); // ok, deduced as T
}
else {
return fib_ce(n-1)+fib_ce(n-2); // we already deduced T, so sticking with it
}
}
Ok, I think I found the answer, need to refrain from auto and letting the compiler work the return type out here. The following works fine:
#include<iostream>
template <typename T>
constexpr T fib_ce(T n) {
return (n>1) ? fib_ce(n-1)+fib_ce(n-2) : 1;
}
int main() {
std::cout<<fib_ce(4)<<"\n";
}
Related
This is a good answer already, however, they passed arbitrary numbers of arguments as the parameters when I tried to do the same with arguments as typename (don't know the exact word) like this for example:
int sum=0;
int func()
{
return sum;
}
template <int first, int ... rest>
int func()
{
sum += first;
return func(rest...); //Error C2660 'func': function does not take 4 arguments
/*
return func<rest...>(); this also doesn't work: Error 'int func(void)': could not deduce template argument for 'first' and 'func': no matching overloaded function found
*/
}
int main()
{
cout << func<1,2,3,4,5>();
}
Why there's an error there? Are there any possible fixes? Also, I'm required to pass the argument as typenames, not parameters.
First of all, the "base" function also needs to be a template.
Then to differentiate the two templates, the parameter-pack template needs to take at least two template arguments.
And lastly, you can solve this without the global sum variable, but using the addition in the return statement.
Putting it all together:
template <int first>
int func()
{
return first;
}
template <int first, int second, int ...rest>
int func()
{
return first + func<second, rest...>();
}
For a simple use case as a sum of values, there are many ways (as in Some programmer dude and P Kramer answers).
I'll show you a variant of the recursive solution (Some programmer dude's answer) that isn't particular useful in this case but can come useful in other circumstances (avoiding code repetition when the ground function make something consistent and equal to the recursive version): instead of a ground case version that receive and manage the last value, a ground version that receive a defaulted type and do nothing (return zero, in the sum case):
template <typename = void>
int func ()
{ return 0; }
so you can write the recursive version as follows, without second
template <int first, int ... rest>
int func ()
{ return first + func<rest...>(); }
The trick is in the recursive call: func<rest...>()
When the ...rest template pack isn't empty, the recursive call func<rest...>() invoke the recursive func().
But when the ...rest template pack is empty, the recursive call func<rest...>() become func<>() that doesn't matches the recursive func() (at least a template integer value is required) but matches (thanks to the default void type) func<void>(), so the ground func() function.
If you want to return the sum of a parameter pack and you're okay with a slightly different syntax, you can use fold expressions from C++17 onward or build up recursion with 'if constexpr'
template<typename... args_t>
static constexpr auto sum(args_t&&... values)
{
return (values + ...);
}
// the sum is evaluated at compile time
static_assert(sum(1, 2, 3, 4) == 10ul);
// or like this without fold
template<int value, int... values>
constexpr int sum2()
{
if constexpr (sizeof...(values) > 0)
{
return value + sum2<values...>();
}
else
{
return value;
}
};
static_assert(sum2<1,2,3,4>() == 10);
Just for curiosity here is the version without recursion:
// C++11
template<typename... Ts>
void dummy(Ts... t)
{
}
template<typename T>
T addValue(T& sum, T value)
{
sum += value;
return 0;
}
template<typename SumType, typename... Ts>
SumType sumVariadicArgs(Ts... t)
{
SumType sum = 0;
dummy(addValue(sum, t)...);
return sum;
}
int main()
{
int sum = sumVariadicArgs<int>(1, 2, 3);
double sum2 = sumVariadicArgs<double>(1.0, 2.0, 3.0);
return 0;
}
I wrote a Y combinator like such:
template <class F>
struct Y{
F f;
Y(F _f) : f{_f} {}
template<class...arg_t>
auto operator()(arg_t&&...arg) {return f(*this,std::forward<arg_t>(arg)...);}
};
It works, but when I tried to define a factorial
auto fact = Y{[](auto&& self, int n) {
if (n<=1) return 1;
return n*self(n-1);}};
it would compile, but when I called it like f(3) clang got stuck on deducing the return type. With an explicit return type, it all worked fine. Is this a limitation of the template deduction? Is there a work-around?
I don't believe there is a way around it. You create a lambda with the following definition:
[](auto&& self, int n) {
if (n<=1) return 1;
return n*self(n-1);
}
This translates to:
struct lambda
{
template <typename T1>
constexpr auto operator()(T1&&self, int n) const
{
if (n<=1)
return 1;
return n*self(n-1);
}
};
Given that code, your compiler should deduce the return type as the common type of the 2 return statements.
With your template instation, it first needs to know the return type of your instantiation before it calculate the answer of that instantiation.
For this specific case, it might still be possible to deduce it correctly. What happens if you add extra indirections in between and recourse back to your type?
Type deduction is applied to the two return statements of the Y combinator, unconditionally, because the information held by the variable n is not a constant expression (an expression that is known by the compiler at compilation time). So the fixed point is not found by type deduction.
If n's value is known at compilation time, type deduction will succeed, example:
struct fact_overloads{
template<class Self,int n>
constexpr auto
operator()(Self&& self, std::integral_constant<n>){
if constexpr (n<=1) return 1;
else return n * self(std::integral_constant<n-1>{});
};
};
auto fact = Y{fact_overloads{}};
But such a function has a limited set of use cases because the value of n must be know at compil time.
I ran into a piece of code I do not follow. Consider the following 2 methods.
template <typename T>
auto FindElementV1(std::vector<T> elementList, const T& element) {
return std::find(elementList.begin(), elementList.end(), element);
}
template <typename T>
auto FindElementV2(std::vector<T> elementList, const T& element) -> typename decltype(elementList)::iterator {
return std::find(elementList.begin(), elementList.end(), element);
}
I can understand FindElementV2 working as the return type for that method is specified using a decltype. But Why does FindElementV1 work with no return type specified? Is V1 a standard compliant piece of code?
Below is the full working example. Complied with gcc 6.3
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
template <typename T>
auto FindElementV1(std::vector<T> elementList, const T& element) {
return std::find(elementList.begin(), elementList.end(), element);
}
int main() {
std::vector<int> vec = {1,4,2,4,3,5,3,5,3,6};
auto it = FindElementV1(vec, 5); //< Why does this work without a return type in the method?
cout<<*it<<endl;
}
[dcl.spec.auto]
If the declared return type of the function contains a placeholder type, the return type of the function is deduced from non-discarded return statements, if any, in the body of the function
and also
If a function with a declared return type that contains a placeholder type has multiple non-discarded return statements, the return type is deduced for each such return statement. If the type deduced is not the same in each deduction, the program is ill-formed.
A discarded statement is one that appears in a non-taken branch of a constexpr if statement [stmt.if].
C++14 gave us the ability to write functions with deduced return type:
auto foo() { return 5; }
In C++11, this is ill-formed - you need to specify the return type somehow. In C++14, we can conservatively deduce the return type from the return statements. By conservatively, I mean that if there is more than one - they all need to be the same type, and if you recurse, you need to recurse 2nd and not 1st.
The deduction follows the normal template deduction rules. So this:
auto foo(int& i) { return i; }
returns an int, not int&.
All of which is to say, yes, FindElementV1 is a perfectly valid function template... as of C++14.
I was thinking about the implicit templates of C++14, and I'm trying to declare a function to match an specific argument type (SFINAE and traits still give me headaches). I'm not sure how to explain what I want, but I'm trying to make a Y combinator (just to see if it's possible, not intended for production).
I'm trying to declare a function:
template<typename T>
my_traits<T>::return_type Y(T t) {
// ...
};
Such that T is a function (or a functor) that matches
std::function<R(F, Args...)>
// where F (and above return_type) will be
std::function<R(Args...)>
Which would take any number of arguments, but the first should be a function with the same return type and the same arguments (except this function itself). The first parameter to the operator () of the functor is a template.
The usage I want to achieve:
auto fib = [](auto myself, int x) {
if(x < 2)
return 1;
return myself(x - 1) + myself(x - 2);
};
// The returned type of fib should be assignable to std::function<int(int)>
I wasn't able to take the return type of the T type (because of the overloaded operator ()). What I'm trying to make is possible? How could I make it?
Edit:
Seeing it from a different angle, I'm trying to make this work:
struct my_functor {
template<typename T>
char operator () (T t, int x, float y) { /* ... */ };
};
template<typename T>
struct my_traits {
typedef /* ... */ result_type;
/* ... */
};
// I want this to be std::function<char(int, float)>, based on my_functor
using my_result =
my_traits<my_functor>::result_type;
It is not possible in C++14 return type deduction to deduce int(int) out of int(T, int) as OP desires.
However, we can mask the first parameter of the result using the following approach. The struct YCombinator is instantiated with a non-recursive function object member, whose first argument is a version of itself without the first argument. YCombinator provides a call operator that receives the arguments of the non-recursive function and then returns its function object member after substituting itself for the first argument. This technique allows the programmer to avoid the messiness of myself(myself, ...) calls within the definition of the recursive function.
template<typename Functor>
struct YCombinator
{
Functor functor;
template<typename... Args>
decltype(auto) operator()(Args&&... args)
{
return functor(*this, std::forward<Args>(args)...);
}
};
A make_YCombinator utility template allows for a streamlined usage pattern. This compiles run runs in GCC 4.9.0.
template<typename Functor>
decltype(auto) make_YCombinator(Functor f) { return YCombinator<Functor> { f }; }
int main()
{
auto fib = make_YCombinator([](auto self, int n) -> int { return n < 2 ? 1 : self(n - 1) + self(n - 2); });
for (int i = 0; i < 10 ; ++i)
cout << "fib(" << i << ") = " << fib(i) << endl;
return 0;
}
Since the non-recursive function is not defined at time that the recursive function is defined, in general the recursive function must have an explicit return type.
Edit:
However, it may be possible for the compiler to deduce the return type in certain cases if the programmer takes care to indicate the return type of the recursive function before use of the non-recursive function. While the above construction requires an explicit return type, in the following GCC 4.9.0 has no problem deducing the return type:
auto fib = make_YCombinator([](auto self, int n) { if (n < 2) return 1; return self(n - 1) + self(n - 2); });
To pin this down just a bit further, here is a quote from the draft C++14 standard on return type deduction [7.1.6.4.11]:
If the type of an entity with an undeduced placeholder type is needed
to determine the type of an expression, the program is ill-formed.
Once a return statement has been seen in a function, however, the
return type deduced from that statement can be used in the rest of the
function, including in other return statements. [ Example:
auto n = n; // error, n’s type is unknown
auto f();
void g() { &f; } // error, f’s return type is unknown
auto sum(int i) {
if (i == 1)
return i; // sum’s return type is int
else
return sum(i-1)+i; // OK, sum’s return type has been deduced
}
—end example ]
It's a really hacky approach, and has severe limitations, but here it goes:
First, we need a class that pretends to support every possible operation (as far as possible), such as the fake_anything class. Note that this isn't perfect since at a minimum . and :: won't work. To fake a functor, we give it a function call operator:
template<class... Ts> fake_anything operator()(Ts&&...) const;
Knowing that the lambda has only one operator(), and that operator() has only one template parameter allows us to extract its signature with decltype(&T::operator()<fake_anything>).
For this to work, the lambda's return type must be explicitly specified; it can't use deduction, since otherwise the deduced return types will probably conflict.
Finally we can obtain the other arguments to the lambda and the return type using the standard partial specialization approach:
template<class T>
struct extract_signature;
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...)> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...) const> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
// other cv- and ref-qualifier versions omitted - not relevant to lambdas
// we can also static_assert that none of Args is fake_anything, or reference to it, etc.
And add an alias template to hide all the ugliness of the hack:
template<class T>
using signature_t = typename extract_signature<decltype(&T::template operator()<fake_anything>)>::type;
And finally we can check that
static_assert(std::is_same<signature_t<decltype(fib)>,
std::function<int(int)>>::value, "Oops");
Demo.
The limitations:
The return type of operator() must be explicitly specified. You cannot use automatic return type deduction, unless all of the return statements return the same type regardless of the return type of the functor.
The faking is very imperfect.
This works for operator() of a particular form only: template<class T> R operator()(T, argument-types...) with or without const, where the first parameter is T or a reference to possibly cv-qualified T.
This used to work some weeks ago:
template <typename T, T t>
T tfunc()
{
return t + 10;
}
template <typename T>
constexpr T func(T t)
{
return tfunc<T, t>();
}
int main()
{
std::cout << func(10) << std::endl;
return 0;
}
But now g++ -std=c++0x says:
main.cpp: In function ‘constexpr T func(T) [with T = int]’:
main.cpp:29:25: instantiated from here
main.cpp:24:24: error: no matching function for call to ‘tfunc()’
main.cpp:24:24: note: candidate is:
main.cpp:16:14: note: template<class T, T t> T tfunc()
main.cpp:25:1: warning: control reaches end of non-void function [-Wreturn-type]
clang++ -std=c++11 says that template's parameters of tfunc<T, t>() are ignored because invalid.
Is that a bug, or a fix ?
PS:
g++ --version => g++ (GCC) 4.6.2 20120120 (prerelease)
clang++ --version => clang version 3.0 (tags/RELEASE_30/final) (3.0.1)
The parameter t is not a constant expression. Hence the error. It should be also noted that it cannot be a constant expression.
You can pass the constant expression as argument, but inside the function, the object (the parameter) which holds the value, is not a constant expression.
Since t is not a constant expression, it cannot be used as template argument:
return tfunc<T, t>(); //the second argument must be a constant expression
Maybe, you want something like this:
template <typename T, T t>
T tfunc()
{
return t + 10;
}
template <typename T, T t> //<---- t became template argument!
constexpr T func()
{
return tfunc<T, t>();
}
#define FUNC(a) func<decltype(a),a>()
int main()
{
std::cout << FUNC(10) << std::endl;
}
Now it should work : online demo
I get the feeling that constexpr must also be valid in a 'runtime' context, not just at compile-time. Marking a function as constexpr encourages the compiler to try to evaluate it at compile-time, but the function must still have a valid run-time implementation.
In practice, this means that the compiler doesn't know how to implement this function at runtime:
template <typename T>
constexpr T func(T t)
{
return tfunc<T, t>();
}
A workaround is to change the constructor such that it takes its t parameter as a normal parameter, not as a template parameter, and mark the constructor as constexpr:
template <typename T>
constexpr T tfunc(T t)
{
return t + 10;
}
template <typename T>
constexpr T func(T t)
{
return tfunc<T>(t);
}
There are three levels of 'constant-expression-ness':
template int parameter, or (non-VLA) array size // Something that must be a constant-expression
constexpr // Something that may be a constant-expression
non-constant-expression
You can't really convert items that are low in that list into something that is high in that list, but obviously the other route it possible.
For example, a call to this function
constexpr int foo(int x) { return x+1; }
isn't necessarily a constant-expression.
// g++-4.6 used in these few lines. ideone doesn't like this code. I don't know why
int array[foo(3)]; // this is OK
int c = getchar();
int array[foo(c)]; // this will not compile (without VLAs)
So the return value from a constexpr function is a constant expression only if all the parameters, and the implementation of the function, can be completed at executed at compile-time.
Recap the question: You have two functions which take a parameter of type T. One takes its parameter as a template parameter, and the other as a 'normal' parameter.
I'm going to call the two functions funcT and funcN instead of tfunc and func.
You wish to be able to call funcT from funcN. Marking the latter as a constexpr doesn't help.
Any function marked as constexpr must be compilable as if the constexpr wasn't there. constexpr functions are a little schizophrenic. They only graduate to full constant-expressions in certain circumstances.
It would not be possible to implement funcN to run at runtime in a simple way, as it would need to be able to work for all possible values of t. This would require the compiler to instantiate many instances of tfunc, one for each value of t. But you can work around this if you're willing to live with a small subset of T. There is a template-recursion limit of 1024 in g++, so you can easily handle 1024 values of T with this code:
#include<iostream>
#include<functional>
#include<array>
using namespace std;
template <typename T, T t>
constexpr T funcT() {
return t + 10;
}
template<typename T, T u>
constexpr T worker (T t) {
return t==0 ? funcT<T,u>() : worker<T, u+1>(t-1);
}
template<>
constexpr int worker<int,1000> (int ) {
return -1;
}
template <typename T>
constexpr T funcN(T t)
{
return t<1000 ? worker<T,0>(t) : -1;
}
int main()
{
std::cout << funcN(10) << std::endl;
array<int, funcN(10)> a; // to verify that funcN(10) returns a constant-expression
return 0;
}
It uses a function worker which will recursively convert the 'normal' parameter t into a template parameter u, which it then uses to instantiate and execute tfunc<T,u>.
The crucial line is return funcT<T,u>() : worker<T, u+1>(t-1);
This has limitations. If you want to use long, or other integral types, you'll have to add another specialization. Obviously, this code only works for t between 0 and 1000 - the exact upper limit is probably compiler-dependent. Another option might be to use a binary search of sorts, with a different worker function for each power of 2:
template<typename T, T u>
constexpr T worker4096 (T t) {
return t>=4096 ? worker2048<T, u+4096>(t-4096) : worker2048<T, u>(t);
}
I think this will work around the template-recursion-limit, but it will still require a very large number of instantiations and would make compilation very slow, if it works at all.
Looks like it should give an error - it has no way of knowing that you passed in a constant value as t to func.
More generally, you can't use runtime values as template arguments. Templates are inherently a compile-time construct.