I want to transform all objects - which are of type, say, char - from one container c and store the results - which are of type foo - in a different container v. The desired conversion function is an overloaded function - call it to_foo.
Consider the following example:
#include <algorithm>
#include <vector>
struct foo {};
foo to_foo(char) { return {}; }
foo to_foo(int) { return {}; }
int main()
{
std::array<char, 1> c;
std::vector<foo> v(c.size());
// cannot determine which instance of overloaded function "to_foo" is intended:
std::transform(c.begin(), c.end(), v.begin(), to_foo);
// ok:
std::transform(c.begin(), c.end(), v.begin(), [](auto const& ch) { return to_foo(ch); });
}
While it's somehow plausible to me that in the first transform the compiler doesn't know which overload of to_foo it should take (on the other, couldn't he deduce it from the value_type of the iterators?), I don't understand why he is able to do so in the second transform. What's happening here?
You have to explicitly tell it which overload to use by casting to_foo:
std::transform(c.begin(), c.end(), v.begin(), static_cast<foo (*)(char)>(to_foo));
The type of the unary operation parameter of std::transform is a different template argument than the one used for the iterators. So it has to use the type of the value you pass to deduce the template argument. to_foo's type is ambiguous, so it can't complete that process. Casting the function pointer to a specific overload type makes it unambiguous.
In the second form, the lambda is a callable object, and the use of auto makes the object's () operator a function template:
struct NamelessGenericLambda {
template <typename T>
foo operator ()(T const& ch) { return to_foo(ch); }
};
std::transform(c.begin(), c.end(), v.begin(), NamelessGenericLambda{});
The type is clear so it can instantiate the std::transform template.
Then somewhere inside std::transform it will try to instantiate the operator () template by passing a char. Because it passes an unambiguous type, the compiler deduces ch is a char. Then it picks the right overload of to_foo using regular overload resolution.
Related
I have a struct with a method called call which has a const overload. The one and only argument is a std::function which either takes a int reference or a const int reference, depending on the overload.
The genericCall method does exactly the same thing but uses a template parameter instead of a std::function as type.
struct SomeStruct {
int someMember = 666;
void call(std::function<void(int&)> f) & {
f(someMember);
std::cout << "call: non const\n";
}
void call(std::function<void(const int&)> f) const& {
f(someMember);
std::cout << "call: const\n";
}
template <typename Functor>
void genericCall(Functor f) & {
f(someMember);
std::cout << "genericCall: non const\n";
}
template <typename Functor>
void genericCall(Functor f) const& {
f(someMember);
std::cout << "genericCall: const\n";
}
};
When I now create this struct and call call with a lambda and auto & as argument the std::function always deduces a const int & despite the object not being const.
The genericCall on the other hand deduces the argument correctly as int & inside the lamdba.
SomeStruct some;
some.call([](auto& i) {
i++; // ?? why does auto deduce it as const int & ??
});
some.genericCall([](auto& i) {
i++; // auto deduces it correctly as int &
});
I have no the slightest clue why auto behaves in those two cases differently or why std::function seems to prefer to make the argument const here. This causes a compile error despite the correct method is called. When I change the argument from auto & to int & everything works fine again.
some.call([](int& i) {
i++;
});
When I do the same call with a const version of the struct everything is deduced as expected. Both call and genericCall deduce a const int & here.
const SomeStruct constSome;
constSome.call([](auto& i) {
// auto deduces correctly const int & and therefore it should
// not compile
i++;
});
constSome.genericCall([](auto& i) {
// auto deduces correctly const int & and therefore it should
// not compile
i++;
});
If someone could shine some light on this I would be very grateful!
For the more curious ones who want to dive even deeper, this problem arose in the pull request: https://github.com/eclipse-iceoryx/iceoryx/pull/1324 while implementing a functional interface for an expected implementation.
The issue is that it's a hard error to try to determine whether your lambda is Callable with const int & returning void, which is needed to determine whether you can construct a std::function<void(const int&)>.
You need to instantiate the body of the lambda to determine the return type. That's not in the immediate context of substituting a template argument, so it's not SFINAE.
Here's an equivalent error instantiating a trait.
As #aschepler notes in the comments, specifying a return type removes the need to instantiate the body of your lambda.
The problem is that generic lambdas (auto param) are equivalent to a callable object whose operator() is templated. This means that the actual type of the lambda argument is not contained in the lambda, and only deduced when the lambda is invoked.
However in your case, by having specific std::function arguments, you force a conversion to a concrete type before the lambda is invoked, so there is no way to deduce the auto type from anything. There is no SFINAE in a non-template context.
With no specific argument type, both your call are valid overloads. Actually any std::function that can match an [](auto&) is valid. Now the only rule is probably that the most cv-qualified overload wins. You can try with a volatile float& and you will see it will still choose that. Once it choose this overload, the compilation will fail when trying to invoke.
Consider I have a custom type (which I can extend):
struct Foo {
int a;
string b;
};
How can I make an instance of this object assignable to a std::tie, i.e. std::tuple of references?
Foo foo = ...;
int a;
string b;
std::tie(a, b) = foo;
Failed attempts:
Overloading the assignment operator for tuple<int&,string&> = Foo is not possible, since assignment operator is one of the binary operators which have to be members of the left hand side object.
So I tried to solve this by implementing a suitable tuple-conversion operator. The following versions fail:
operator tuple<int,string>() const
operator tuple<const int&,const string&>() const
They result in an error at the assignment, telling that "operator = is not overloaded for tuple<int&,string&> = Foo". I guess this is because "conversion to any type X + deducing template parameter X for operator=" don't work together, only one of them at once.
Imperfect attempt:
Hence I tried to implement a conversion operator for the exact type of the tie:
operator tuple<int&,string&>() const Demo
operator tuple<int&,string&>() Demo
The assignment now works since types are now (after conversion) exactly the same, but this won't work for three scenarios which I'd like to support:
If the tie has variables of different but convertible types bound (i.e. change int a; to long long a; on the client side), it fails since the types have to fully match. This contradicts the usual use of assigning a tuple to a tuple of references which allows convertible types.(1)
The conversion operator needs to return a tie which has to be given lvalue references. This won't work for temporary values or const members.(2)
If the conversion operator is not const, the assignment also fails for a const Foo on the right hand side. To implement a const version of the conversion, we need to hack away const-ness of the members of the const subject. This is ugly and might be abused, resulting in undefined behavior.
I only see an alternative in providing my own tie function + class together with my "tie-able" objects, which makes me force to duplicate the functionality of std::tie which I don't like (not that I find it difficult to do so, but it feels wrong to have to do it).
I think at the end of the day, the conclusion is that this is one drawback of a library-only tuple implementation. They're not as magic as we'd like them to be.
EDIT:
As it turns out, there doesn't seem to be a real solution addressing all of the above problems. A very good answer would explain why this isn't solvable. In particular, I'd like someone to shed some light on why the "failed attempts" can't possibly work.
(1): A horrible hack is to write the conversion as a template and convert to the requested member types in the conversion operator. It's a horrible hack because I don't know where to store these converted members. In this demo I use static variables, but this is not thread-reentrant.
(2): Same hack as in (1) can be applied.
Why the current attempts fail
std::tie(a, b) produces a std::tuple<int&, string&>.
This type is not related to std::tuple<int, string> etc.
std::tuple<T...>s have several assignment-operators:
A default assignment-operator, that takes a std::tuple<T...>
A tuple-converting assignment-operator template with a type parameter pack U..., that takes a std::tuple<U...>
A pair-converting assignment-operator template with two type parameters U1, U2, that takes a std::pair<U1, U2>
For those three versions exist copy- and move-variants; add either a const& or a && to the types they take.
The assignment-operator templates have to deduce their template arguments from the function argument type (i.e. of the type of the RHS of the assignment-expression).
Without a conversion operator in Foo, none of those assignment-operators are viable for std::tie(a,b) = foo.
If you add a conversion operator to Foo,
then only the default assignment-operator becomes viable:
Template type deduction does not take user-defined conversions into account.
That is, you cannot deduce template arguments for the assignment-operator templates from the type Foo.
Since only one user-defined conversion is allowed in an implicit conversion sequence, the type the conversion operator converts to must match the type of the default assignment operator exactly. That is, it must use the exact same tuple element types as the result of std::tie.
To support conversions of the element types (e.g. assignment of Foo::a to a long), the conversion operator of Foo has to be a template:
struct Foo {
int a;
string b;
template<typename T, typename U>
operator std::tuple<T, U>();
};
However, the element types of std::tie are references.
Since you should not return a reference to a temporary,
the options for conversions inside the operator template are quite limited
(heap, type punning, static, thread local, etc).
There are only two ways you can try to go:
Use the templated assignment-operators:
You need to publicly derive from a type the templated assignment-operator matches exactly.
Use the non-templated assignment-operators:
Offer a non-explicit conversion to the type the non-templated copy-operator expects, so it will be used.
There is no third option.
In both cases, your type must contain the elements you want to assign, no way around it.
#include <iostream>
#include <tuple>
using namespace std;
struct X : tuple<int,int> {
};
struct Y {
int i;
operator tuple<int&,int&>() {return tuple<int&,int&>{i,i};}
};
int main()
{
int a, b;
tie(a, b) = make_tuple(9,9);
tie(a, b) = X{};
tie(a, b) = Y{};
cout << a << ' ' << b << '\n';
}
On coliru: http://coliru.stacked-crooked.com/a/315d4a43c62eec8d
As the other answers already explain, you have to either inherit from a tuple (in order to match the assignment operator template) or convert to the exact same tuple of references (in order to match the non-templated assignment operator taking a tuple of references of the same types).
If you'd inherit from a tuple, you'd lose the named members, i.e. foo.a is no longer possible.
In this answer, I present another option: If you're willing to pay some space overhead (constant per member), you can have both named members and tuple inheritance simultaneously by inheriting from a tuple of const references, i.e. a const tie of the object itself:
struct Foo : tuple<const int&, const string&> {
int a;
string b;
Foo(int a, string b) :
tuple{std::tie(this->a, this->b)},
a{a}, b{b}
{}
};
This "attached tie" makes it possible to assign a (non-const!) Foo to a tie of convertible component types. Since the "attached tie" is a tuple of references, it automatically assigns the current values of the members, even though you initialized it in the constructor.
Why is the "attached tie" const? Because otherwise, a const Foo could be modified via its attached tie.
Example usage with non-exact component types of the tie (note the long long vs int):
int main()
{
Foo foo(0, "bar");
foo.a = 42;
long long a;
string b;
tie(a, b) = foo;
cout << a << ' ' << b << '\n';
}
will print
42 bar
Live demo
So this solves problems 1. + 3. by introducing some space overhead.
This kind of does what you want right? (assumes that your values can be linked to the types of course...)
#include <tuple>
#include <string>
#include <iostream>
#include <functional>
using namespace std;
struct Foo {
int a;
string b;
template <template<typename ...Args> class tuple, typename ...Args>
operator tuple<Args...>() const {
return forward_as_tuple(get<Args>()...);
}
template <template<typename ...Args> class tuple, typename ...Args>
operator tuple<Args...>() {
return forward_as_tuple(get<Args>()...);
}
private:
// This is hacky, may be there is a way to avoid it...
template <typename T>
T get()
{ static typename remove_reference<T>::type i; return i; }
template <typename T>
T get() const
{ static typename remove_reference<T>::type i; return i; }
};
template <>
int&
Foo::get()
{ return a; }
template <>
string&
Foo::get()
{ return b; }
template <>
int&
Foo::get() const
{ return *const_cast<int*>(&a); }
template <>
string&
Foo::get() const
{ return *const_cast<string*>(&b); }
int main() {
Foo foo { 42, "bar" };
const Foo foo2 { 43, "gah" };
int a;
string b;
tie(a, b) = foo;
cout << a << ", " << b << endl;
tie(a, b) = foo2;
cout << a << ", " << b << endl;
}
Major downside is that each member can only be accessed by their types, now, you could potentially get around this with some other mechanism (for example, define a type per member, and wrap the reference to the type by the member type you want to access..)
Secondly the conversion operator is not explicit, it will convert to any tuple type requested (may be you don't want that..)
Major advantage is that you don't have to explicitly specify the conversion type, it's all deduced...
This code works for me. I'd love it if someone could point out anything wrong with it.
Simple Version on Compiler Explorer
More Generic Version on Compiler Explorer
#include <tuple>
#include <cassert>
struct LevelBounds final
{
int min;
int max;
operator std::tuple<int&, int&>() { return {min, max}; }
};
int main() {
int a, b;
auto lb = LevelBounds{30, 40};
std::tie(a, b) = lb;
assert(30 == a);
assert(40 == b);
return 0;
}
In the following code,
std::transform (source.begin(), source.end(), // start and end of source
dest.begin(), // start of destination
(int(*)(int const&)) addValue<int,5>); // operation
Can somebody break down the cast,
(int(*)(int const&))
where addValue is Nontype Function Template give as
template <typename T, int VAL>
T addValue (T const& x)
{
return x + VAL;
}
Thanks.
The cast (int(*)(int const&)) is a cast to the type int(*)(int const&), which is the type "pointer to function taking int const& and returning int".
Since addValue<int, 5> already has the type "function taking int const& and returning int" (and will decay to function pointer when passed by value), the cast is unnecessary in this context.
An example of when such a cast would be useful would be to disambiguate between multiple function templates with the same name. If, in addition to the addValue definition shown, we had this also:
template <typename T, int VAL>
void addValue(T& x) {
x += VAL;
}
then specifying addValue<int, 5> alone would be ambiguous. Telling the compiler what type addValue is supposed to have after instantiation would tell it to use int addValue<int, 5>(int const&) instead of void addValue<int, 5>(int&), so it would know which template to pick.
I am to implement a set of class templates and two special variables, _1 and _2.
They should make the following a legal code:
// Sort ascending
std::sort(a, a+5, _1 > _2);
// Output to a stream
std::for_each(a, a+5, std::cout << _1 << " ");
// Assign 100 to each element
std::for_each(a, a+5, _1 = 100);
// Print elements increased by five 5
std::transform(a, a+5, std::ostream_iterator<int>(std::cout, " "), _1 + 5);
I suppose that _1 * 5 should also yield an unary function, as well as _1 / 5 etc.
No boost allowed
No lambdas allowed
Now I have very little experience with templates and template metaprogramming, so I don't even know where to start and what the structure of my class templates should look like. I am especially confused as I don't know if inside my class templates I will have to write implementations for all these operator=, operator>>, operator+, ...-, ...*, .../ separately - or there is a more generic way to do it.
I will be particularly grateful to an answer with an example of implementation of these operators; templates still seem like a great mess to me.
Well! That is a tricky homework problem, indeed! But, it's also a very good problem to work on and to learn from.
I think that the best way to answer this is for you to start off with simple use cases and incrementally build up your solution.
For example, suppose that you have the following std::vector<int> to work with:
std::vector<int> vec;
vec.push_back(4);
vec.push_back(-8);
vec.push_back(1);
vec.push_back(0);
vec.push_back(7);
You'll obviously want to allow the following use case:
std::for_each(vec.cbegin(), vec.cend(), _1);
But how to allow this? First you'll need to define _1 and then you'll need to implement an "anything goes" overload of the function call operator for the type of _1.
The way that Boost Lambda and Boost Bind define placeholders objects _1, _2, ... is to make them have a dummy type. For example, the _1 object might have the type placeholder1_t:
struct placeholder1_t { };
placeholder1_t _1;
struct placeholder2_t { };
placeholder2_t _2;
Such a "dummy type" is frequently, informally called a tag type. There are many C++ libraries and indeed the STL that rely on tag types (e.g. std::nothrow_t). They are used to pick the "right" function overload to execute. Essentially, dummy objects are created having a tag type and these are passed into a function. The function does not use the dummy object in any way (in fact, most of the time a parameter name is not even specified for it), but by the existence of that extra parameter, the compiler is able to pick the correct overload to call.
Let's extend the definition of placeholder1_t by adding overloads of the function call operator. Remember that we want it to accept anything, so the overloads of the function call operator will themselves be templated on the argument type:
struct placeholder1_t
{
template <typename ArgT>
ArgT& operator()(ArgT& arg) const {
return arg;
}
template <typename ArgT>
const ArgT& operator()(const ArgT& arg) const {
return arg;
}
};
That's it! Our simplest of use cases will now compile and run:
std::for_each(vec.cbegin(), vec.cend(), _1);
Of course, it basically amounts to a no-op.
Let's now work on _1 + 5. What should that expression do? It should return a unary functional object that, when invoked with an argument (of some unknown type), the result is that argument plus 5. Making this more generic, the expression is unary-functional-object + object. The returned object is itself a unary functional object.
The type of the returned object needs to be defined. It will be a template with two template type parameters: the unary functional type and the type of the object that is being added to the result of the unary functional:
template <typename UnaryFnT, typename ObjT>
struct unary_plus_object_partfn_t;
"partfn" refers to a functional type representing partial application of the binary + operator. Instances of this type need a copy of the unary functional object (having type UnaryFnT) and the other object (having type ObjT):
template <typename UnaryFnT, typename ObjT>
struct unary_plus_object_partfn_t
{
UnaryFnT m_fn;
ObjT m_obj;
unary_plus_object_partfn_t(UnaryFnT fn, ObjT obj)
: m_fn(fn), m_obj(obj)
{
}
};
Okay. The function call operator also needs to be overloaded to allow for any argument. We'll use the C++11 decltype feature to refer to the type of an expression as we don't know what it is beforehand:
template <typename UnaryFnT, typename ObjT>
struct unary_plus_object_partfn_t
{
UnaryFnT m_fn;
ObjT m_obj;
unary_plus_object_partfn_t(UnaryFnT fn, ObjT obj)
: m_fn(fn), m_obj(obj)
{
}
template <typename ArgT>
auto operator()(ArgT& arg) const -> decltype(m_fn(arg) + m_obj) {
return m_fn(arg) + m_obj;
}
template <typename ArgT>
auto operator()(const ArgT& arg) const -> decltype(m_fn(arg) + m_obj) {
return m_fn(arg) + m_obj;
}
};
It's starting to get complicated, but there are no surprises in this code. It essentially says that the function call operator is overloaded to accept practically any argument. It will then call m_fn (the unary functional object) on the argument and add m_obj to the result. The return type is the decltype of m_fn(arg) + m_obj.
Now that the type is defined, we can write the overload of binary operator + accepting an object of type placeholder1_t on the left:
template <typename ObjT>
inline unary_plus_object_partfn_t<placeholder1_t, ObjT> operator+(const placeholder1_t& fn, ObjT obj)
{
return unary_plus_object_partfn_t<placeholder1_t, ObjT>(fn, obj);
}
We now can compile and run the second use case:
std::transform(vec.cbegin(), vec.cend(), std::ostream_iterator<int>(std::cout, " "), _1 + 5);
std::cout << std::endl;
which outputs:
9 -3 6 5 12
This is basically all that you need to do to solve the problem. Think about how you can write custom functional types, instances of which can be returned by overloads of operators.
EDIT: Improved the overloads of function call operators by employing pass-by-reference.
EDIT2: In some cases it will be necessary to store a reference to an object rather than a copy of it. For example, to accommodate std::cout << _1, you will need to store a reference to std::cout in the resulting functional object because the std::ios_base copy constructor is private, and it is impossible to copy construct objects of any class derived from std::ios_base including std::ostream.
To allow for std::cout << _1, you might want to write a ref_insert_unary_partfn_t template. Such a template, like the example of unary_plus_object_partfn_t above, would be templated on an object type and a unary functional type:
template <typename ObjT, typename UnaryFnT>
struct ref_insert_unary_partfn_t;
Instances of instantiations of this template will need to store a reference to an object of type ObjT as well as a copy of a unary functional object of type UnaryFnT:
template <typename ObjT, typename UnaryFnT>
struct ref_insert_unary_partfn_t
{
ObjT& m_ref;
UnaryFnT m_fn;
ref_insert_unary_partfn_t(ObjT& ref, UnaryFnT fn)
: m_ref(ref), m_fn(fn)
{
}
};
Add overloads of the function call operator as before as well as overloads of the insertion operator, <<.
In the case of std::cout << _1, the returned object would have the type ref_insert_unary_partfn_t<std::basic_ostream<char>, placeholder1_t>.
A simple example:
template <typename T>
class Parameter
{
};
template <typename T>
struct Ascending
{
bool operator()(T left, T right)
{
return left < right;
}
};
template <typename T>
Ascending<T> operator > (Parameter<T> p1, Parameter<T> p2)
{
return Ascending<T>();
}
int main()
{
std::vector<int> vec;
vec.push_back(3);
vec.push_back(6);
vec.push_back(7);
vec.push_back(2);
vec.push_back(7);
std::vector<int>::iterator a = vec.begin();
Parameter<int> _1;
Parameter<int> _2;
std::sort(a, a+4, _1 > _2);
}
I'm playing around with lambda functions in gcc 4.6.2, and would like to implement a templated "map" function like this:
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, const std::function<B(A)> f) {
std::vector<B> rv;
rv.resize(orig.size());
std::transform(begin(orig), end(orig), begin(rv), f);
return rv;
}
This doesn't work, because the test code:
int main(int argc, char **argv) {
std::vector<int> list;
list.push_back(10);
list.push_back(20);
list.push_back(50);
std::vector<int> transformed = map(list, [](int x) -> int { return x + 1; });
std::for_each(begin(transformed), end(transformed), [](int x) { printf("-> %d\n", x); });
return 0;
}
gives this error:
test.cpp:49:80: error: no matching function for call to ‘map(std::vector<int>&, main(int, char**)::<lambda(int)>)’
test.cpp:49:80: note: candidate is:
test.cpp:6:49: note: template<class A, class B> std::vector<B> map(const std::vector<A>&, std::function<B(A)>)
If I remove the templating, and use a vector directly, it compiles fine:
std::vector<int> map(const std::vector<int>& orig, const std::function<int(int)> f) {
std::vector<int> rv;
rv.resize(orig.size());
std::transform(begin(orig), end(orig), begin(rv), f);
return rv;
}
so it must be a problem with the way I'm defining the template.
Has anyone run into this before? I know lambdas are incredibly new.
You don't need to use std::function. Just make the predicate parameter a template value. For example,
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, B f) {
std::function<> is more useful as a member value type or for defining non-templated code.
The problem is that the compiler can't figure out what to use for B. In order to determine that type it wants to use the function<> you pass in for f, but you don't pass an std::function<> directly. You pass in something you expect to be used to construct a function<>. And in order to do that implicit construction it needs to know the type of argument. So you've got this circular dependency where the type of argument depends on what you pass in, but what gets passed in depends on the type of argument.
You can break this circular dependency by specifying the template parameters, such as map_<int,int>(list, [](int x) -> char { return x + 1; });
(although I see the functor actually returns a char, not an int, so if the type deduction worked for you here you'd be getting back a vector<char> which cannot be converted to a vector<int> when you assign the result to transformed)
However as has been pointed out, generally templates take functors as just a plain template type:
template<typename A,typename Func>
auto map_(const std::vector<A>& orig, Func f) -> std::vector<decltype(f(A()))> {
std::vector<decltype(f(A()))> rv;
/*...*/
}
(we use the trailing return type because we need to use the expression f in the return type, which isn't available unless the return type comes afterwards.)
This allows the template to deduce the functor type directly and avoids any type conversions and best allows for optimization.
It's also customary to use iterators as arguments on these sorts of functions, in which case your function is just a wrapper around std::transform, so you can just use that directly. I'm not sure there's a whole lot of value in a special version that deals with vectors specifically.
I'm tackling with lambdas too and i noticed that you can declare a function pointer in a function definition's parameter list and when you make a call to that function you can pass a lambda expression as an argument if it matches the function prototype of course.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
template <typename T,typename C>
struct map {
typedef C (*F)(const T&);
std::vector<C> rv;
map () {}
map (const std::vector<T>& o,F f) {
rv.resize(o.size());
std::transform (o.begin(),o.end(),rv.begin(),f);
}
~map () {}
operator std::vector<C> () const {
return rv;
}
};
int main () {
std::vector<int> asd(5,12);
std::vector<char> transformed=map<int,char>(asd,[](const int& x)->char {return x+1;});
std::copy (transformed.begin(),transformed.end(),std::ostream_iterator<int>(std::cout," "));
}