Consider the following code that tries to use SFINAE for providing different method implementations depending on a template parameter.
#include <type_traits>
#include <iostream>
template<bool S>
struct C{
template<typename std::enable_if<!S>::type* = nullptr>
int foo(int i){
return i + 1;
}
template<typename std::enable_if<S>::type* = nullptr>
int foo(int i){
return i;
}
};
int main(){
C<true> c1;
C<false> c2;
std::cout << c1.foo(0) << c2.foo(0) << std::endl;
}
This example is inspired by the reference page of std::enable_if. As you see, struct C<S> has two foo methods. One should be enabled if S is true, and the other if S is false. However, the code does not compile but raises the following errors:
src/test.cpp: In instantiation of ‘struct C<true>’:
src/test.cpp:19:12: required from here
src/test.cpp:7:8: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
int foo(int i){
^
src/test.cpp: In instantiation of ‘struct C<false>’:
src/test.cpp:20:13: required from here
src/test.cpp:12:8: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
int foo(int i){
So it seems that the compiler completelty ignores SFINAE and raises an error once it finds that a type is not enabled. What am I doing wrong here?
S is not a template parameter of the method, it is a template parameter of the class. During instantiation of the class, S has been determined, and as a result, std::enable_if<!S_>::type is no longer type-dependent so cannot be used the way you're using it. You can, as Nawaz answered, solve this by using overloading, but you can also make S a template parameter of the method -- sort of:
#include <type_traits>
#include <iostream>
template<bool S>
struct C {
template<bool S_ = S, typename std::enable_if<!S_>::type* = nullptr>
int foo(int i){
return i + 1;
}
template<bool S_ = S, typename std::enable_if<S_>::type* = nullptr>
int foo(int i) {
return i;
}
};
int main(){
C<true> c1;
C<false> c2;
std::cout << c1.foo(0) << c2.foo(0) << std::endl;
}
template<typename std::enable_if<!S>::type* = nullptr>
int foo(int i)
{
return i + 1;
}
This is NOT function template, because there is NO template parameter for this (supposedly) function template. It is not even function. The code is simply ill-formed.
Note that S is a template parameter of the enclosing class template, not the function (template).
The following code would be correct (but wouldn't solve your problem):
template<typename SS, typename std::enable_if<!SS>::type* = nullptr>
int foo(int i)
{
//etc
}
Here typename SS defines template parameter for the function template. Your function doesn't do so. The template parameter used in std::enable_if must be a template parameter of the same function template.
Use function overloading to solve your problem:
template<bool S>
struct C
{
int foo(int i)
{
return foo_impl(std::integral_constant<bool, S>(), i);
}
private:
int foo_impl(std::true_type, int i)
{
return i + 1;
}
int foo_impl(std::false_type, int i)
{
return i;
}
};
That is the general implementation. But in this specific case, when you're using bool as template parameter, then another solution could be this:
template<bool S>
struct C
{
int foo(int i)
{
return S ? foo_a(i) : foo_b(i);
}
private:
int foo_a(int i)
{
return i + 1;
}
int foo_b(int i)
{
return i;
}
};
Since S is known to the compiler, so I believe the compiler would eliminate the branching in return S ? foo_a(i) : foo_b(i); and would instead write either return foo_a(i); or return foo_b(i); based on the value of S, effectively producing faster code.
Related
I'd like to write a type alias template that resolves to the const of the template parameter for most types, like so:
template <typename T>
using TypeAlias = const T;
but for a particular type, say int, it simply resolves to T.
I've tried doing this with std::conditional, as well as specialization of structs containing the type alias, but in all cases, the compiler is unable to infer the type. My questions are: what am I doing wrong in the examples below? and How does one do this correctly?
Edit: I'm working in a very large codebase that handles a large number of types, and adds const to all of them in the definition of TypeAlias (which is actually a more complicated type, basically a container templated over const T). I'm trying to modify this codebase to accept a new type which cannot be const, while making minimal modifications. Explicitly specifying the type in all templated functions like foo isn't a workable solution. What I'm really looking for is a way to modify TypeAlias, and little to nothing else.
example 1:
#include <stdio.h>
#include <type_traits>
template <typename T>
using TypeAlias = typename std::conditional<std::is_same<int, T>::value,
T, typename std::add_const<T>::type>::type;
template <typename T>
void foo(TypeAlias<T> var) {
printf("var = %f\n", static_cast<double>(var));
}
int main(int argc, char *argv[]) {
const int a = 1;
const float b = 2;
const double c = 3;
foo(a);
foo(b);
foo(c);
return 0;
}
example 2:
template <typename T>
struct TypeHolder {
using type = const T;
};
template <>
struct TypeHolder<int> {
using type = int;
};
template <typename T>
void foo(typename TypeHolder<T>::type var) {
printf("var = %f\n", static_cast<double>(var));
}
int main(int argc, char *argv[]) {
int a = 1;
const float b = 2;
const double c = 3;
foo(a);
foo(b);
foo(c);
return 0;
}
Here's another way to remove const for a specific set of types, just add an overload and use SFINAE to constrain based on whether the deduced type is in the set or not:
#include <iostream>
#include <type_traits>
template <class T, class... Ts>
inline constexpr bool is_any_v = (... || std::is_same_v<T, Ts>);
template <class T>
inline constexpr bool int_or_short_v = is_any_v<T, int, short>;
template <class T>
std::enable_if_t<!int_or_short_v<T>> foo(const T) { std::cout << "const" << std::endl; }
template <class T>
std::enable_if_t<int_or_short_v<T>> foo(T) { std::cout << "non-const" << std::endl; }
int main() {
const int a = 1;
const short b = 2;
const float c = 3;
const double d = 4;
foo(a);
foo(b);
foo(c);
foo(d);
}
Try it on godbolt.org
In C++20, even easier:
#include <iostream>
#include <concepts>
template <class T, class... Ts>
concept any_of = (... || std::same_as<T, Ts>);
void foo(const auto) { std::cout << "const" << std::endl; }
void foo(any_of<int, short> auto) { std::cout << "non-const" << std::endl; }
int main() {
const int a = 1;
const short b = 2;
const float c = 3;
const double d = 4;
foo(a);
foo(b);
foo(c);
foo(d);
}
Try it on godbolt.org
As was mentioned in the comments, this is a non-deduced context so the template types will not be deduced. This is actually one of the tricks you can use to force the caller so explicitly set the template parameter.
What you could do is use if constexpr to differentiate between your two (or more) cases:
void foo_for_int(int x) { /* do something for ints */ }
template <typename T> foo_for_others(T const x) { /* do something for other types */ }
template <typename T>
void foo(T && t)
{
if constexpr (std::is_same_v<int, T>)
{
foo_for_int(t); // no need to forward an int
}
else
{
foo_for_others(std::forward<T>(t));
}
}
I understand how lambda functions work. The problem is that the program calls the function recursiveFunction() before the compiler has deduced what 'auto' should be. The thing is, it's a recursive function so the function itself is in the definition.
#include <iostream>
using namespace std;
template <class T>
class Class {
public:
int foo(int x);
};
template <class T>
int Class<T>::foo(int x) {
auto recursiveFunction = [=](int n)->int {
if (n <= 1) return 1;
else return n*recursiveFunction(n-1);
};
return recursiveFunction(x);
}
int main() {
Class<int> c;
cout << c.foo(5) << endl;
return 0;
}
I've also implemented this using a class using templates in case that factors into the problem.
Here's the error message:
main.cpp: In instantiation of 'int Class<T>::foo(int) [with T = int]':
main.cpp:21:20: required from here
main.cpp:14:40: error: use of 'recursiveFunction' before deduction of 'auto'
else return n*recursiveFunction(n-1);
Thanks!
Answered here:
The second snippet runs into [dcl.spec.auto]/10:
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.
The type of foo is needed to determine the type of the expression foo within the lambda body, but at that point you haven't deduced foo's type yet, so the program is ill-formed.
Further references:
lambda capture during initialization should be an error
"a variable declared with an auto specifier cannot appear in its own initializer"
Fix: https://godbolt.org/z/np3ULe
#include <iostream>
#include <functional>
template <class T>
class Class {
public:
int foo(int x);
};
template <class T>
int Class<T>::foo(int x) {
std::function<int(int)> fac = [&fac](int n) -> int {
if (n <= 1)
return 1;
else
return n * fac(n - 1);
};
return fac(x);
}
int main() {
Class<int> c;
std::cout << c.foo(5) << std::endl;
return 0;
}
Couple possible answers:
type-erasure; you don't actually need to know the type of recursiveFunction, just enough to have pinned down its signature.
So you could just do without the problematic auto and associated deduction, and promise to know the type in advance.
template <class T>
int Class<T>::foo(int x) {
std::function<int(int)> recursiveFunction;
recursiveFunction = [=](int n)->int {
if (n <= 1) return 1;
else return n*recursiveFunction(n-1);
};
return recursiveFunction(x);
}
If this wasn't just an oversimplified example, you don't appear to actually be capturing any state, so you could just use a normal recursive function instead of a lambda.
namespace {
int recursiveFunction(int) {
if (n <= 1) return 1;
else return n*recursiveFunction(n-1);
}
}
int Class<T>::foo(int x) {
return recursiveFunction(x);
}
If the lambda aspect was actually important, you're looking for the "Y combinator". Which is not very straightforward in C++, but something like:
#include <iostream>
#include <functional>
template <class T>
class Class {
public:
int foo(int x);
};
template<class F>
struct function_traits;
template<class R, class T>
struct function_traits<R(T)> {
typedef R return_type;
typedef T arg_type;
};
// function pointer
template<class R, class... Args>
struct function_traits<R(*)(Args...)> : public function_traits<R(Args...)>{}};
template <typename Signature>
auto y (std::function<typename function_traits<Signature>::return_type(typename function_traits<Signature>::arg_type, std::function<Signature>)> f)
-> std::function<Signature>
{
return [f](typename function_traits<Signature>::arg_type n) -> typename function_traits<Signature>::return_type { return f(n,y(f)); };
}
template <class T>
int Class<T>::foo(int x) {
return y<int(int)>([=](int n, auto recursiveFunction) -> int {
if (n <= 1) return 1;
else return n*recursiveFunction(n-1);
})(5);
}
int main() {
Class<int> c;
std::cout << c.foo(5) << std::endl;
return 0;
}
If you want to avoid std::function, you might do (requires C++14 for generic lambda):
int Class<T>::foo(int x) {
auto recursiveFunction = [](auto recFunc, int n) -> int
{
if (n <= 1) return 1;
else return n * recFunc(recFunc, n - 1);
};
return recursiveFunction(recursiveFunction, x);
}
Demo
I have the following code:
#include <iostream>
using namespace std;
template <class T>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
template <class T1, class T2>
void function(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
// your code goes here
function(get_num, 3);
return 0;
}
I need to call the get_num() function with an int argument. But compiler gets this error:
prog.cpp: In function ‘int main()’: prog.cpp:21:21: error: no matching
function for call to ‘function(<unresolved overloaded function type>,
int)’ function(get_num, 3);
^ prog.cpp:15:6: note: candidate: template<class T1, class T2> void function(T1 (*)(T2), T2) void function(T1
(*callback)(T2), T2 arg) {
^~~~~~~~ prog.cpp:15:6: note: template argument deduction/substitution failed: prog.cpp:21:21: note: couldn't deduce
template parameter ‘T1’ function(get_num, 3);
How can it be done ?
After removing template <class T> from int get_num(int) to get a normal overload set, you can use Some programmer dude’s answer.
In this answer I want to elaborate how you can still use a function pointer based parameter.
If you switch the arguments to function at least gcc is able to deduce it:
template <typename T, typename U>
void function2(T arg, U(*callback)(T)) {
callback(arg);
}
clang doesn’t like it when you use U there, so if your return types will always be the same as your arguments, you can use T twice:
template <typename T>
void function2(T arg, T(*callback)(T)) {
callback(arg);
}
To resolve disambiguities like the one in your error message in general, you can also do the overload resolution manually with static_cast:
function(static_cast<float(*)(float)>(&get_num), 3.0f);
function(static_cast<int(*)(int)>(&get_num), 3);
One problem is that you have different types for return-type and argument-type for function, but in reality both are the same.
That means you could do something like
template<typename T, typename F = T(T)>
void function(F callback, T arg)
{
callback(arg);
}
The template argument F is just to simplify the callback argument declaration.
You have a template <class T> in front of your int get_num(int k). Lets assume for a moment it isnt there, then this works:
Sometimes you cannot change the function into a template, but need to work with function pointers to a function that has several overloads. The way to choose the right overload is to specify the type of the function pointer (because for different overloads the function pointers are of different type).
typedef int (* int_get_num_t)(int);
int main() {
int_get_num_t correct_overload = get_num;
function(correct_overload, 3);
return 0;
}
In case the int get_num(int k) is really supposed to be a template (then why the float one isnt?) then you simply have to pick the template version:
int_get_num_t correct_overload = get_num<int>;
where actually you could pass any type instead of int as your template get_num always takes an int and returns an int irrespective of the template parameter.
And finally... you actually dont need the second overload for get_num but you need only one template. And in that case you still need to pick the right template to get the function pointer:
template <typename T>
T get_num(T k) { return k + 3; }
template <class T1, class T2>
void function(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
int_get_num_t correct_overload = get_num<int>;
function(correct_overload, 3);
return 0;
}
Here's the one using the C++ functors.
#include <iostream>
using namespace std;
template<class T>
struct get_num : public std::unary_function<T,T>
{
T operator()(const T& k) {
return k+3;
}
};
template< class T1, class T2 >
void function( T1 fun, T2 arg)
{
fun(arg);
cout << fun(arg) << endl;
}
int main()
{
function(get_num<int>(), 3);
return 0;
}
The following code will work:
#include <iostream>
using namespace std;
template<typename T>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
template<typename T1, typename T2> // Maybe here you want the `typename`, not the `class`
void f(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
// your code goes here
f(get_num<int>, 3); // The key point is here!
return 0;
}
The reason you get the compiling error is the compiler could not deduce the type T if you just use get_num, because all the arguments are nothing with the type T.
You have to specify the type of function
#include <iostream>
#include <string>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
std::string get_num (double a)
{
return "this is a string " + std::to_string(a);
}
template <class T1, class T2>
using callback = T1(*)(T2);
template <class T1, class T2>
void function(callback<T1, T2> function, T2 arg) {
std:: cout << function(arg) << std::endl;
}
int main() {
// your code goes here
function<int, int>(get_num, 3);
function<std::string, double>(get_num, 3);
system("pause");
return 0;
}
Why 2 different template arguments? -The OP's question is not about optimization, it is about
How to pass the specific callback to a template function?
So, this is one of many implementations, solving the specific error.
I allowed myself to simplify a bit Your code. This should work fine:
#include <iostream>
using namespace std;
template <class T>
T get_num(T k) {
return k + 3;
}
template <class T1, class T2>
void function(T1 callback, T2 arg) {
callback(arg);
}
int main() {
function(get_num<int>, 3);
return 0;
}
I want to provide an solution which differs a bit.
I explain it inside the code to make it hopefully more comfortable to read and understand:
// create a helper class,
// which collects all callable classes to build one callable object later
template<class... Ts> struct funcs : Ts... { using Ts::operator()...; };
template<class... Ts> funcs(Ts...) -> funcs<Ts...>;
// instead of free functions, build objects with methods
// and use operator() instead of function names.
// this makes it easier to "understand" that this will be an callable object
struct Func1
{
int operator()(int k) {
return k + 3;
}
};
struct Func2
{
float operator()(float k) {
return k + 3;
}
};
// adapt your code to this:
template <class T1, class T2>
auto function(T1 callback, T2 arg) {
return callback(arg);
}
// and finaly you can use it this way, also with return types
// the central hack is:
// funcs{ Func1(), Func2() }
// this will generate a callable object with all the overloads
// from the inserted callable objects
int main() {
// your code goes here
std::cout << function(funcs{ Func1(), Func2() }, 3) << std::endl;
std::cout << function(funcs{ Func1(), Func2() }, (float)7.999) << std::endl;
return 0;
}
I would like to be able to name to a templated function in a template.
Since one can name a templated class using the "template template" syntax, and since one can name a function using the "function pointer" syntax, I was wondering whether there is a syntax (or a proposal) to name a function in a template without specifying to templates.
template<typename t_type>
struct A {
t_type value;
};
template<template<typename> class t_type>
struct B {
t_type<int> value;
};
template<int added>
constexpr int C (int value) {
return value + added;
}
template<int (*function)(int)>
constexpr int D (int value) {
return function(value);
}
// GOAL: Template argument referring to templated function
/*template<template<int> int (*function)(int)>
constexpr int E (int value) {
return function<1>(value);
}*/
int main() {
B<A> tt_good;
int fp_good = D< &C<1> >(0);
/*int fp_fail = E< &C >(0);*/
return 0;
}
One possible work-around for anyone interested in this functionality to first wrap the function D in a struct with a call method named (for example) "method", pass the struct into E as a "template template" parameter, and then call "method" in E.
The reason that I don't like this approach is that it requires a wrapper structure for every variadic function that might be used in this way.
Unfortunately, you cannot pass function templates as template parameters. The closest you can get is by using generic functors:
#include <iostream>
template <typename F>
void call(F f)
{
f("hello, world\n");
}
int main()
{
call([](auto value) { std::cout << value; });
}
If you don't have C++14 generic lambdas, you can write your own functors by hand:
#include <iostream>
template <typename F>
void call(F f)
{
f("hello, world\n");
}
struct print
{
template <typename T>
void operator()(T value) const
{
std::cout << value;
}
};
int main()
{
call(print());
}
Say I have the following code:
#include <iostream>
#include <functional>
template <int func(int)>
struct S : std::unary_function<int, int>
{
int operator()(int x) const
{
return func(x);
}
};
int foo(int x)
{
return x;
}
int main()
{
S<foo> s;
std::cout << s(42) << std::endl;
}
This works okay as a way of wrapping up a function inside of a functor, which means it can be used in other templated functions (like sort, for example (assuming the functor had the right signature)). I don't want to create a functor struct for every possible return/argument type (and realistically I can't), and so I tried the following:
template <template <typename R, // Make the return type and argument type template parameters!
typename A> R func(A)>
struct S : std::unary_function<R, A>
{
R operator()(A arg) const
{
return func(arg);
}
};
That didn't work; it gave me compilation errors. So then I tried:
template <typename R, typename A, R func(A)>
struct S : std::unary_function<R, A>
{
R operator()(A arg) const
{
return func(arg);
}
};
Which did work. Unfortunately though, I had to change instantiations of S to be S<int, int, foo> s; instead of the nicer S<foo> s;.
Is it at all possible to templatize the function passed as a template argument such that I can do S<foo> s; and not hard code the return type and argument type of the function in S?
My google-foo hasn't been able to find a specific answer.
Edit: Now I'm wondering if this isn't possible. I just thought of "what if foo is an overloaded function?" There wouldn't be, as far as I know, a way to know which foo to use when saying S<foo> s; and thus explicitly stating return/argument type is necessary. Is this correct thinking, and does this mean that the answer to my first question is "No, it's not possible"?
Unfortunately, I think it's the only way to prevent necessary conversions for passing functions.
But you can add function templates to help you deduce the types of (1) function args (2) function returns, like codes below:
template < typename R, typename A >
R result_of( R(A) );
template < typename R, typename A >
A arg0_of( R(A) );
Then you can use them to construct wanted function objects and let compilers do possible optimizations:
#define get_call( f ) call_t< decltype(result_of(f)), \
decltype(arg0_of(f)), f >()
// same as the class 'S'
template < typename R, typename A,
R unary( A ) >
struct call_t : std::unary_function<A,R> {
R operator()( A arg ) const {
return unary( arg );
}
};
Use the utility:
int neg( int arg ) {
return -arg;
}
auto s = get_call( neg );
cout << s( 1 ) << endl; // outputs: -1
It works too on function templates. Of course, you have to pass argument(s) to the template:
template < typename T >
T square( T arg ) {
return arg * arg;
}
template <>
int square( int arg ) {
cout << "square<int>()" << endl;
return arg * arg;
}
auto sq = get_call( square<int> );
cout << sq( 12 ) << endl; // outputs: square<int>()
// 144
Edit: for overloaded functions, you can do conversions to tell compilers which version you wanna invoke:
int cube( int arg ) {
return arg * arg * arg;
}
float cube( float arg ) {
return arg * arg * arg;
}
typedef float (*chosen)( float );
auto cu = get_call( (chosen)cube );
cout << showpoint << cu( 4 ) << endl; // outputs: 64.0000
You seem to want to have a non-type template template parameter. However, the only legal syntax for template template parameters is template < template-parameters > class. ("A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression." § 14.3.3)
You could create a templated class whose constructor argument was a function pointer, but I'm guessing that you're worried that will create an indirect function call.
That is not possible. It is the same problem in principle as the following one: you wish to write just A<100> where A is defined as:
template<T N>
struct A {};
Given N is 100, T turns out to be int. Fine. That is deducible by human mind, but not by the compilers even if they be 100% conformant to the C++11 Standard. I've exactly the same problem here:
Pretty-print types and class template along with all its template arguments
--
So the alternative solution I think is this:
template <typename R, typename A>
struct S : std::unary_function<R, A>
{
typedef R (*Fun)(A);
Fun func;
S(Fun f) : func(f) {}
R operator()(A arg) const
{
return func(arg);
}
};
And then define MakeS function as:
template<typename R, typename A>
S<R,A> MakeS(R (*fun)(A))
{
return S<R,A>(fun);
}
Which you can use it as:
auto s = MakeS(foo);
Or, simply this:
S<int,int> s(foo);
The downside with this alternative is that the function foo doesn't have any chance to be inlined now.
Does this work for you?
It may not be as nice as S<foo> but keeps the arguments as 1 at the point of instantiation.
int f(int) { return 0; }
template<class R, class A> struct S
{
typedef R(*FTYPE)(A);
typedef R RET;
typedef A ARG;
};
template<class R, class A> S<R, A> FW(R(f)(A));
template<class T> struct F : std::unary_function<typename T::RET, typename T::ARG>
{
};
int main()
{
F<decltype(FW(f))> o;
}