I have a pair of function templates defined like so:
template<typename CollectionType>
Foo<CollectionType> f(const CollectionType& v)
{
return Foo<CollectionType>(v); // copies v into a member variable
}
template<typename CollectionType>
Foo<CollectionType> f(CollectionType&& v)
{
return Foo<CollectionType>(std::move(v)); // moves v into a member variable
}
If I call f as below:
std::vector<int> v;
f(v);
The VC++ compiler favors the && overload, apparently because it is less specialized. I would like the const& overload to be called in this case--the && version is intended for constructions like f(ReturnAVector()). Is there a way to achieve this without manually specifying the template argument?
After a fair amount of effort, I came up with this:
template<typename CollectionType>
Foo<CollectionType> f(const CollectionType& v)
{
return Foo<CollectionType>(v); // copies v into a member variable
}
template<typename CollectionType>
typename std::enable_if<std::is_rvalue_reference<CollectionType&&>::value,
Foo<typename std::remove_reference<CollectionType>::type>>::type
f(CollectionType&& v)
{
return Foo<CollectionType>(std::move(v)); // moves v into a member variable
}
But wow; is that really the simplest way to get what I'm after?
With:
std::vector<int> v;
f(v);
you call f(std::vector<int>&) so
template<typename CollectionType>
Foo<CollectionType> f(CollectionType&& v)
is an exact match (universal reference) CollectionType is std::vector<int>&
whereas
template<typename CollectionType>
Foo<CollectionType> f(const CollectionType& v)
requires a const promotion.
A possible solution is to add a version non const:
template<typename CollectionType>
Foo<CollectionType> f(CollectionType& v)
or to forward your argument, something like:
template<typename CollectionType>
Foo<typename std::remove_reference<CollectionType>::type>
f(CollectionType&& v)
{
return Foo<typename std::remove_reference<CollectionType>::type>(std::forward<CollectionType>(v));
}
The second overload is always an exact match. So there is in fact no need for the first overload and it can only cause ambiguity. Instead of moving, you should forward the argument.
template<typename CollectionType>
Foo<CollectionType> f(CollectionType&& v)
{
return Foo<CollectionType>(std::forward<CollectionType>(v));
}
Scott Meyers has given an excellent explanation of this: http://scottmeyers.blogspot.nl/2012/11/universal-references-in-c11-now-online.html
Related
I want to write a function my_func that can be called as so, but does not care that v is a std::vector, it could be any STL container. A bit like std::for_each:
std::vector<std::string> v = {...};
my_func(v.begin(), v.end());
But I cannot figure out the function signature.
void my_func(??? i1, ??? i2)
{
std::for_each(i1, i2, ...); // dumb example implementation
}
I am not great at template programming so even looking at the function declaration for std::for_each is not helping me.
Is there an easy implementation or is this fundamentally going to get messy with template vars?
It depends on how generic you want the function to be. If the iterator types have to match, then
template <typename T>
void my_func(T i1, T i2)
{
std::for_each(i1,i2,...); //dumb example implementation
}
is all you need. If you want them to be able to be different, then you just need another template parameter like
template <typename T, typename U>
void my_func(T i1, U i2)
{
std::for_each(i1,i2,...); //dumb example implementation
}
Finally, if you don't like dealing with templates you can use a lambda instead and let the compiler take care of this for you. That would give you
auto my_func = [](auto i1, auto i2)
{
std::for_each(i1,i2,...); //dumb example implementation
};
You could write a templated function
template<typename Iterator>
void my_func(Iterator startIter, const Iterator endIter)
{
std::for_each(startIter, endIter, /* lambda */);
}
In case of wondering, how to pass the third parameter of the std::for_each, you could provide one more template parameter
const auto defaultCallable = [](auto element){ }; // does nothing
template<typename Iterator, typename Callable = decltype(defaultCallable)>
void my_func(Iterator startIter, const Iterator endIter, Callable func = {})
{
std::for_each(startIter, endIter, func);
}
The syntax is not too obscure! The following way uses the range for at the point of use:
template <template<typename...> class Iterable, typename T>
void foo(
const Iterable<T>& y // the container
){
for (auto&& e : y){
// e is the 'thingy' in the container.
}
}
and you can pass any iterable container of arbitrary type to foo.
As You may (not) know using std::minmax with auto and temporary arguments may be dangerous. Following code for example is UB because std::minmax returns pair of references, not values:
auto fun(){
auto res = std::minmax(3, 4);
return res.first;
}
I would like to ask if there is possibility to make std::minmax function act safely or at least safer without any overhead? I came up with a solution like this, but I am not completely sure if it is equivalent to current minmax as generated assembly is different for stl-like implementation and mine. So the question is: what are the possible problems/drawbacks of my implementation of minmax in relation to std-like one:
//below is std-like minmax
template< class T >
constexpr std::pair<const T&,const T&> std_minmax( const T& a, const T& b ){
return (b < a) ? std::pair<const T&, const T&>(b, a)
: std::pair<const T&, const T&>(a, b);
}
//below is my minmax implementation
template< class T >
constexpr std::pair<T, T> my_minmax( T&& a, T&& b ){
return (b < a) ? std::pair<T, T>(std::forward<T>(b), std::forward<T>(a))
: std::pair<T, T>(std::forward<T>(a), std::forward<T>(b));
}
Live demo at godbolt.org
As some of You claim it is unclear what I am asking, I would like to reword a bit what I want. I would like to write function which works exactly like std::minmax, but if given one temporary value - returns std::pair<T, T> instead of std::pair<const T &, const T &>. Secondly, while doing it I would like to avoid any unnecessary moving, copying of data and so forth.
I am not exactly sure what are you trying to achieve. You wrote:
without any overhead
but your solution will copy lvalue arguments. Is it what you want?
Anyway, you cannot use two forwarding references with the same template parameter this way, since it will fail if both function arguments have different categories:
template <typename T> void f(T&& a, T&& b) { }
int main() {
int a = 3;
f(a, 1); // error: template argument deduction/substitution failed
}
For the first function argument, T would be deduced as int&, and for second as int.
If you want to remove any copying, the only possibility is the member of the resulting pair to be:
a (const) lvalue reference to the corresponding function argument in case it is an lvalue,
a value moved from that argument if is it an rvalue.
I don't think this is possible to achieve. Consider:
std::string a("hello");
auto p = minmax(a, std::string("world"));
Here the resulting type would be std::pair<std::string&, std::string>. However, in case of
auto p = minmax(a, std::string("earth"));
the resulting type would be different, namely std::pair<std::string, std::string&>.
Therefore, the resulting type would depend on a runtime condition (which generally requires runtime polymorphism).
UPDATE
Out of curiosity, I just came up with a wrapper that can hold some object either by (const) pointer or by value:
template <typename T>
class val_or_ptr {
std::variant<T, const T*> v_;
public:
val_or_ptr(const T& arg) : v_(&arg) { }
val_or_ptr(T&& arg) : v_(std::move(arg)) { }
const T& get() const { return v_.index() ? *std::get<const T*>(v_) : std::get<T>(v_); }
};
With that, you can define minmax as:
template <typename T, typename U,
typename V = std::enable_if_t<std::is_same_v<std::decay_t<T>, std::decay_t<U>>, std::decay_t<T>>>
std::pair<val_or_ptr<V>, val_or_ptr<V>> minmax(T&& a, U&& b) {
if (b < a) return { std::forward<U>(b), std::forward<T>(a) };
else return { std::forward<T>(a), std::forward<U>(b) };
}
Live demo is here: https://wandbox.org/permlink/N3kdI4hzllBGFWVH
This is very basic implementation, but it should prevent copying both from lvalue and rvalue arguments of minmax.
One solution is when T is an r-value reference then copy it instead of returning an r-value reference:
#include <utility>
template<class T>
std::pair<T, T> minmax(T&& a, T&& b) {
if(a < b)
return {a, b};
return {b, a};
}
When the argument is an r-value reference T is deduced as a non-reference type:
int main() {
int a = 1;
int const b = 2;
minmax(1, 1); // std::pair<int, int>
minmax(a, a); // std::pair<int&, int&>
minmax(b, b); // std::pair<const int&, const int&>
}
With C++17 it is possible to use constexpr if to tie lvalue args and copy everything else. With C++11 I would probably think twice before building an angle brackets moster with a scary look for such a simple use case.
godbolt, coliru
template <typename T>
decltype(auto) minmax(T&& x, T&& y)
{
if constexpr(std::is_lvalue_reference_v<decltype(x)>)
return std::minmax(std::forward<T>(x), std::forward<T>(y));
else {
auto const res = std::minmax(x, y);
return std::make_pair(res.first, res.second);
}
}
To support mixed l/r values you probably need two template params, 4 cases in the if/else, and std::cref(res.xxx) as an argument to std::make_pair for partial.
In order to broaden my understanding of C++11, I'm experimenting with writing functional helpers and seeing if I can make calling them less verbose. Consider the following code:
#include <list>
int timesTwo(int x) { return x*2; }
int timesX(int x, int y) { return x*y; }
class Foo {
public:
Foo(int a) : value(a) {};
int fooTimesTwo() const { return value*2; };
int value;
};
template <class T, class U>
std::list<U> myMap(const std::list<T> &list, const std::function<U(const T &)> &func)
{
std::list<U> result;
for(typename std::list<T>::const_iterator it = list.begin(); it != list.end(); ++it) {
result.push_back(func(*it));
}
return result;
}
int main()
{
std::list<int> numbers = {1,2,3,4,5};
std::list<int> numbers2 = myMap<int,int>(numbers, [] (int x) { return x*2; });
std::list<int> numbers3 = myMap<int,int>(numbers, ×Two);
std::list<int> numbers4 = myMap<int,int>(numbers, std::bind(timesX, 2, std::placeholders::_1));
std::list<Foo> fooList = {Foo(1), Foo(2), Foo(3), Foo(4)};
std::list<int> numbers5 = myMap<Foo,int>(fooList, &Foo::fooTimesTwo);
return 0;
}
Is there anyway to rewrite myMap so that
all four of the calls to it in my code example do not require any template arguments, and...
there's only one general implementation, and I don't have to manually write an overloaded version for each combination of types I want to call it with?
I've tried changing the second argument of myMap to be a third templated type instead of std::function, but it fails because a) the second templated type U can't be inferred, and b) even if it could, the fourth call to myMap will cause an error on line 20 due to &Foo::fooTimesTwo not being a function or function pointer.
I'm willing to consider all of the various features of C++11 to do this, and I don't particularly care if it makes the declaration or definition of myMap obtuse or unreadable. I'm just wondering if it's possible and, if so, what sort of techniques and C++11 features can accomplish it.
You could attempt to implement std::invoke in C++11, but I think it would be really cumbersome.
It's fairly simple to make a function template for a generalized callable:
template <class T, class F>
auto myMap(const std::list<T> &list, F&& func)
-> std::list<typename std::decay<decltype(func(*list.begin()))>::type>
{
using U = typename std::decay<decltype(func(*list.begin()))>::type;
std::list<U> result;
for(typename std::list<T>::const_iterator it = list.begin(); it != list.end(); ++it) {
result.push_back(func(*it));
}
return result;
}
You get expression sfinae for free. Now there's only member function pointer to be taken care of:
template <class T, class F>
auto myMap(const std::list<T> &list, F&& func)
-> std::list<typename std::decay<decltype(((*list.begin()).*func)())>::type>
{
return myMap(list, [=](T const& t){ return (t.*func)(); });
}
Now you can call your functions as expected. demo
While at it, you could replace this ugly for loop with a ranged for:
for(auto const& elem : list) {
results.push_back(func(elem));
}
Or use an algorithm:
std::transform(list.begin(), list.end(), std::back_inserter(result), func);
I need to use different compare functions as unary functions, where one of the values is embedded inside the comparator. To do so I created an adaptor class, something like:
template<typename T, typename Compare>
class CompareAdaptor : private Compare
{
public:
CompareAdaptor(T value)
: mValue(value)
{
}
bool operator()(T v) const
{
return Compare::operator()(v, mValue);
}
private:
T mValue;
};
and now I can define a new unary comparator like:
template<typename T>
using EqualTo = CompareAdaptor<T, std::equal_to<T>>;
template<typename T>
using LessEqual = CompareAdaptor<T, std::less_equal<T>>;
My questions is: Is there a simpler way(without using the adaptor class) to define those unary comparators? I think this is a very common problem and probably you have better solutions.
In C++11, this is as good as it gets. But I'd rather expect the predicate to be directly constructed at the call site :
std::find_if(begin(v), end(v), [limit](int i) { return i < limit; });
In C++14, you could use return type deduction to make a factory fuction :
template <class Comp>
auto predicate(typename Comp::second_argument_type rhs) {
return [c = Comp{}, rhs](typename Comp::first_argument_type lhs) {
return c(lhs, rhs);
};
}
Example call : predicate<std::less<int>>(4) returns the function object.
Live on Coliru
#Quentins answer can also be made compilable in C++11 using std::function as the return type which the lambdas are convertible to:
template <class Comp>
std::function<typename Comp::result_type (typename Comp::first_argument_type)> predicate(typename Comp::second_argument_type rhs)
{
return [rhs](typename Comp::first_argument_type lhs){
Comp c{};
return c(lhs, rhs);
};
}
live on coliru
I'm in the process of writing up an STL-like library for learning purposes. All of the collections extend a class called Iterable which contains wrapping functions for all of the functions found in <algorithm>. For example, it allows vec.each([](T t){...}); which I strongly prefer over the verbose std::for_each. The function giving me problems is count - I want to overload Iterable::count so it combines the behaviour of both std::count and std::count_if depending on the argument type but I'm running into a strange error.
Iterable.h
virtual int count(const T& value) const {
return std::count(begin(), end(), value);
}
virtual int count(std::function<bool(T&)> predicate) {
return std::count_if(begin(), end(), predicate);
}
virtual int count(std::function<bool(const T&)> predicate) const {
return std::count_if(begin(), end(), predicate);
}
main.cpp
Vector<int> vec; // extends Iterable
vec.add(0);
vec.add(1);
vec.count([](int i){ return i == 0; }); // compiles and works fine
vec.count(0); // error c2666: 3 overloads have similar conversions
I should note that changing the count_if wrapper function names to count_if does work and resolves the ambiguity, but I'd prefer to have them named count and also to figure out why there is ambiguity in the first place.
From what I interpret, the compiler is trying to make a new std::function using the template <class F> function(F f) ctor, then runs into the ambiguity. Is that the case? It seems odd since the line below fails to compile as well.
std::function<bool(int)> f(0); // error C2064: term does not evaluate to a function taking 1 arguments
Any insights or potential fixes are much appreciated.
Forgot to say; using visual studio 2012, nov 2012 ctp compiler
std::function<Sig> in the published C++11 standard without errata contains a constructor that thinks it can consume anything, as far as its signature is concerned. If you pass it things it cannot consume (things that are not callable), it fails to compile.
Overload resolution occurs earlier (based on shallower information) than the compile failure. It matches on signatures, not implementations.
A bug report and a fix was proposed, so some C++11 compilers can fix this, and all C++14 compilers must fix this.
VS2012 has limited SFINAE overload resolution capabilities. But one approach would look like:
template<class Sig, class=void>
struct is_filter_on : std::false_type{};
template<class F, class Arg>
struct is_filter_on< F(Arg),
typename std::enable_if<std::is_convertible<
typename std::result_of<F(Arg)>::type
,bool>::value>::type
> : std::true_type{};
which is an attempt at a traits class that tells you if F(Arg) is a bool-returning "filter" on values of type Arg.
template<class X>
size_t count(X&& x) const {
return count( std::forward<X>(x), is_filter_on< X&(T const&) >{} );
}
template<class X>
size_t count(X&& x) {
return count( std::forward<X>(x), is_filter_on< X&(T&) >{} );
}
template<class F>
size_t count(F&& f, std::true_type) const {
return std::count_if( begin(), end(), std::forward<F>(f) );
}
template<class F>
size_t count(F&& f, std::true_type) {
return std::count_if( begin(), end(), std::forward<F>(f) );
}
template<class X>
size_t count(X&& x, std::false_type) const {
return std::count( begin(), end(), std::forward<X>(x) );
}
template<class X>
size_t count(X&& x, std::false_type) {
return std::count( begin(), end(), std::forward<X>(x) );
}
but I have no idea of MSVC2012 will work with the above.
Here I use tag dispatching to pick which version of count I call. The traits class is_filter_on does a test to determine if the pseudo-expression F(Arg) is filter-like. If so, we dispatch to the std::count_if. Otherwise, we dispatch to the std::count version.
The problem is that 0 is ambiguous here, it can be interpreted as a null pointer or an int, which makes it match both the std::function constructor and the more general const T& value (both require a conversion).
If you don't want to change the interface, you can just create a very simple function template to deduce and dispatch the arguments.
C++11 version:
template<typename U>
int count(U&& value) const {
return count_impl(std::forward<U>(value));
}
This works because the function template type deduction rules don't have that ambiguity, they never treat 0 as a null pointer.
So your interface is now:
virtual int count_impl(const T& value) const {
return std::count(v.begin(), v.end(), value);
}
virtual int count_impl(std::function<bool(T&)> predicate) {
return std::count_if(v.begin(), v.end(), predicate);
}
virtual int count_impl(std::function<bool(const T&)> predicate) const {
return std::count_if(v.begin(), v.end(), predicate);
}
template<typename U>
int count(U&& value) const {
return count_impl(std::forward<U>(value));
}
And you can use it naturally:
int main(){
Vector<int> vec; // extends Iterable
vec.count([](int i){ return i == 0; }); // compiles and works fine
vec.count(0); // no problem, calls virtual int count_impl(const T& value) const
}