e.g. I have a function that can handle const T & and T && values:
template <typename T>
/* ... */ foo(const T &) {
std::cout << "const T & as arg" << std::endl;
}
template <typename T>
/* ... */ foo(T &&) {
std::cout << "T && as arg" << std::endl;
}
Is there a way that I can write a single function, that handles both types automatically? As in:
template <typename T>
/* ... */ bar(T t) {
foo(t);
}
So that:
T a;
bar(a); // Handles as const T &
T b;
bar(std::move(b)); // Handles as T &&
Thank you!
You can use reference collapsing and std::forward to forward the argument to the foo function:
template <typename T>
/* ... */ bar(T&& t) {
foo(std::forward<T>(t));
}
Please notice that your foo function will accept rvalues, constant lvalues and non-const lvalues. As an example, given:
const int x = 456;
int y = 123;
then:
foo(123); // foo(T&&)
foo(x); // foo(const T&)
foo(y); // foo(T&&)
Live demo
Related
I am writing a class member function that will take a lambda with a given type T in the function argument. My question is: is it possible to overload the member function at compile-time based on the mutability of the argument? Below is the example:
// T is a given type for class.
template <typename T>
class Wrapper {
T _t;
// For T&
template <typename F, typename R = std::result_of_t<F(T&)>>
std::enable_if_t<std::is_same<R, void>::value> operator()(F&& f) {
f(_t);
}
// For const T&
template <typename F, typename R = std::result_of_t<F(const T&)>>
std::enable_if_t<std::is_same<R, void>::value> operator()(F&& f) const {
f(_t);
}
};
So, what I want is, if the give lambda is with the following signature, the first operator should be invoked.
[](T&) {
...
};
For constant argument, the second should be invoked.
[](const T&) {
}
If you plan to use non-capturing lambdas only, you can rely on the fact that they decay to pointers to functions.
It follows a minimal, working example:
#include<type_traits>
#include<iostream>
template <typename T>
class Wrapper {
T _t;
public:
auto operator()(void(*f)(T &)) {
std::cout << "T &" << std::endl;
return f(_t);
}
auto operator()(void(*f)(const T &)) const {
std::cout << "const T &" << std::endl;
return f(_t);
}
};
int main() {
Wrapper<int> w;
w([](int &){});
w([](const int &){});
}
Otherwise you can use two overloaded functions as it follows:
#include<type_traits>
#include<iostream>
#include<utility>
template <typename T>
class Wrapper {
T _t;
template<typename F>
auto operator()(int, F &&f)
-> decltype(std::forward<F>(f)(const_cast<const T &>(_t))) const {
std::cout << "const T &" << std::endl;
return std::forward<F>(f)(_t);
}
template<typename F>
auto operator()(char, F &&f) {
std::cout << "T &" << std::endl;
return std::forward<F>(f)(_t);
}
public:
template<typename F>
auto operator()(F &&f) {
return (*this)(0, std::forward<F>(f));
}
};
int main() {
Wrapper<int> w;
w([](int &){});
w([](const int &){});
}
Let's say I have some arbitrary complicated overloaded function:
template <class T> void foo(T&& );
template <class T> void foo(T* );
void foo(int );
I want to know, for a given expression, which foo() gets called. For example, given some macro WHICH_OVERLOAD:
using T = WHICH_OVERLOAD(foo, 0); // T is void(*)(int);
using U = WHICH_OVERLOAD(foo, "hello"); // U is void(*)(const char*);
// etc.
I don't know where I would use such a thing - I'm just curious if it's possible.
Barry, sorry for the misunderstanding in my first answer. In the beginning I understood your question in a wrong way. 'T.C.' is right, that it is not possible except in some rare cases when your functions have different result types depending on the given arguments. In such cases you can even get the pointers of the functions.
#include <string>
#include <vector>
#include <iostream>
//template <class T> T foo(T ) { std::cout << "template" << std::endl; return {}; };
std::string foo(std::string) { std::cout << "string" << std::endl; return {}; };
std::vector<int> foo(std::vector<int>) { std::cout << "vector<int>" << std::endl; return {}; };
char foo(char) { std::cout << "char" << std::endl; return {}; };
template<typename T>
struct Temp
{
using type = T (*) (T);
};
#define GET_OVERLOAD(func,param) static_cast<Temp<decltype(foo(param))>::type>(func);
int main(void)
{
auto fPtr1 = GET_OVERLOAD(foo, 0);
fPtr1({});
auto fPtr2 = GET_OVERLOAD(foo, std::string{"hello"});
fPtr2({});
auto fPtr3 = GET_OVERLOAD(foo, std::initializer_list<char>{});
fPtr3({});
auto fPtr4 = GET_OVERLOAD(foo, std::vector<int>{});
fPtr4({});
auto fPtr5 = GET_OVERLOAD(foo, std::initializer_list<int>{});
fPtr5({});
return 0;
}
The output is:
char
string
string
vector<int>
vector<int>
I'm probably far from what you have in mind, but I've spent my time on that and it's worth to add an answer (maybe a completely wrong one, indeed):
#include<type_traits>
#include<utility>
template <class T> void foo(T&&);
template <class T> void foo(T*);
void foo(int);
template<int N>
struct choice: choice<N+1> { };
template<>
struct choice<3> { };
struct find {
template<typename A>
static constexpr
auto which(A &&a) {
return which(choice<0>{}, std::forward<A>(a));
}
private:
template<typename A>
static constexpr
auto which(choice<2>, A &&) {
// do whatever you want
// here you know what's the invoked function
// it's template<typename T> void foo(T &&)
// I'm returning its type to static_assert it
return &static_cast<void(&)(A&&)>(foo);
}
template<typename A>
static constexpr
auto which(choice<1>, A *) {
// do whatever you want
// here you know what's the invoked function
// it's template<typename T> void foo(T *)
// I'm returning its type to static_assert it
return &static_cast<void(&)(A*)>(foo);
}
template<typename A>
static constexpr
auto
which(choice<0>, A a)
-> std::enable_if_t<not std::is_same<decltype(&static_cast<void(&)(A)>(foo)), decltype(which(choice<1>{}, std::forward<A>(a)))>::value, decltype(&static_cast<void(&)(A)>(foo))>
{
// do whatever you want
// here you know what's the invoked function
// it's void foo(int)
// I'm returning its type to static_assert it
return &foo;
}
};
int main() {
float f = .42;
static_assert(find::which(0) == &static_cast<void(&)(int)>(foo), "!");
static_assert(find::which("hello") == &static_cast<void(&)(const char *)>(foo), "!");
static_assert(find::which(f) == &static_cast<void(&)(float&)>(foo), "!");
static_assert(find::which(.42) == &static_cast<void(&)(double&&)>(foo), "!");
}
I'll delete this answer after a short period during the which I expect experts to curse me. :-)
I want to overload two functions based on whether the argument is a temporary object, so I write code like this:
#include <iostream>
void f(int &&)
{
std::cout << "&&" << std::endl;
}
void f(const int&)
{
std::cout << "const &" << std::endl;
}
int main()
{
int i;
f(i);
f(i + 1);
}
And it corrently output:
const &
&&
However, when I change the code to use template like this:
#include <iostream>
template <typename T>
void f(T &&)
{
std::cout << "&&" << std::endl;
}
template <typename T>
void f(const T&)
{
std::cout << "const &" << std::endl;
}
int main()
{
int i;
f(i);
f(i + 1);
}
The output becomes:
&&
&&
What's the problem? How can I optimize for moveable temporary object when using template?
edit:
Actually, this is a test code when I read C++ Primer. It says:
template <typename T> void f(T&&); // binds to nonconst rvalues
template <typename T> void f(const T&); // lvalues and const rvalues
After my experiment, it seems the book makes a mistake here.
template <typename T>
void f(T &&)
{
std::cout << "&&" << std::endl;
}
Uses universal forwarding reference and allows any types with reference collapsing.
You have to use T with a no deducing context as wrapping your code into a struct:
template <typename T>
struct helper
{
void f(T &&)
{
std::cout << "&&" << std::endl;
}
void f(const T&)
{
std::cout << "const &" << std::endl;
}
};
template <typename T>
void f(T &&t)
{
helper<typename std::decay<T>::type>().f(std::forward<T>(t));
}
Live example
I have a problem in my code
Here is simplified version of it :
#include <iostream>
class A
{
public :
template <class T>
void func(T&&)//accept rvalue
{
std::cout<<"in rvalue\n";
}
template <class T>
void func(const T&)//accept lvalue
{
std::cout<<"in lvalue\n";
}
};
int main()
{
A a;
double n=3;
a.func(n);
a.func(5);
}
I expect the output to be :
in lvalue
in rvalue
but it is
in rvalue
in rvalue
why ?!
template <class T> void func(T&&) is universal reference forwarding reference.
To test what you want, try: (Live example)
template <typename T>
class A
{
public:
void func(T&&)//accept rvalue
{
std::cout<<"in rvalue\n";
}
void func(T&)//accept lvalue
{
std::cout<<"in lvalue\n";
}
};
int main()
{
A<double> a;
double n = 3;
a.func(n);
a.func(5.);
}
To build on Jarod42's fine answer, if you want to keep the design of having a primary function template, you can decide based on the deduced type of the universal reference parameter:
#include <iostream>
#include <type_traits>
struct A
{
template <typename T> // T is either U or U &
void func(T && x)
{
func_impl<T>(std::forward<T>(x));
}
template <typename U>
void func_impl(typename std::remove_reference<U>::type & u)
{
std::cout << "lvalue\n";
}
template <typename U>
void func_impl(typename std::remove_reference<U>::type && u)
{
std::cout << "rvalue\n";
}
};
I think the surprise comes from the way the template argument are deduced. You'll get what you expect if you write:
a.func<double>(n);
I have the following bit of code which has two versions of the function foo. I'd like if a variable is passed for the foo that takes an AVar type to be called otherwise if a const is passed for the AConst version to be called.
#include <iostream>
template <typename T>
struct AConst
{
AConst(T x):t(x){}
const T t;
};
template <typename T>
struct AVar
{
AVar(const T& x):t(x){}
const T& t;
};
template <typename T>
void foo(AConst<T> a) { std::cout << "foo AConst\n"; }
template <typename T>
void foo(AVar<T> a) { std::cout << "foo AVar\n"; }
int main()
{
int i = 2;
foo(1);
foo(i);
return 0;
}
Currently the compiler gives me an ambiguity error. Not sure how to resolve it.
UPDATE: Based on Leonid's answer with a slight modification, here is the following solution which works as required:
template <typename T>
void foo_x(AConst<T> a) { std::cout << "foo AConst\n"; }
template <typename T>
void foo_x(AVar<T> a) { std::cout << "foo AVar\n"; }
template <typename T>
void foo(const T& a) { foo_x(AConst<T>(a));}
template <typename T>
void foo(T& a) { foo_x(AVar<T>(a));}
Compiler can not deduce your T.
To help him, simplify parameter type:
template <typename T>
void foo(const T& a) { AConst<T> aa(a); std::cout << "foo AConst\n"; }
template <typename T>
void foo(T& a) { AVar<T> aa(a); std::cout << "foo AVar\n"; }
Use casting to eliminate ambiguity errors. In this case you could cast "1" as an AConst if I remember right. I don't remember the exact syntax for casting to a template type...maybe something like:
foo( (AConst<int>) 1); .. or something to that effect.
The compiler can't select appropriate function. You may want to declare 2 functions with different names:
template <typename T>
void fooConst(AConst<T> a) { std::cout << "foo AConst\n"; }
template <typename T>
void fooVar(AVar<T> a) { std::cout << "foo AVar\n"; }
Or, you may choose to use functions you have this way:
int main()
{
int i = 2;
foo(AConst<int>(1));
foo(AVar<int>(i));
return 0;
}
In general, you doesn't provide enough information to the compiler. You're the only who knows what instance should be used in the main function. Probably, if you would describe in more details what is the purpose of this code, the solution would be more specific.
You could pass in the full class template to the function like so
#include <iostream>
template <typename T>
struct AConst
{
AConst(T x) :t(x){ std::cout << "AConst\n"; }
const T t;
};
template <typename T>
struct AVar
{
AVar(const T& x) :t(x){ std::cout << "AVar\n"; }
const T& t;
};
template <typename T1>
void foo(T1 a){}
int main()
{
int i = 2;
foo<AConst<int>>(1);
foo<AVar<int>>(i);
return 0;
}