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);
}
Related
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;
}
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.
I just read the Boost.Hana tutorial but unfortunately got stuck very early. Could anybody explain to me why to_json for integers is implemented the way it is:
template <typename T>
auto to_json(T const& x) -> decltype(std::to_string(x)) {
return std::to_string(x);
}
I thought that the return type would be simply equivalent to std::string but it is not. If you replace it with std::string the compiler complains about ambiguous function call. What is the difference between std::string and decltype(std::to_string(x))?
This is because SFINAE applies to the expression of the return type.
Not all types can be sent to std::to_string. This makes the expression of the return type resolve to a function that cannot be called with the provided argument. This is a subtitution failure and that triggers SFINAE and the canditate is discarded.
When changing the return type to std::string, then the overload is not discarded, even if std::to_string(x) would not compile, so the function still takes part in the overload set, making the call ambiguous.
There are other places you could put the constraint. Here is some examples:
template<typename T> // in the non traitling return type
decltype(constrait) to_json() {}
// in the template parameters
template<typename T, decltype(void(constraint), 0) = 0>
auto to_json() -> std::string {}
// (less common) in the function parameters
template<typename T>
auto to_json(decltype(void(constraint), 0) = 0) {}
I have a std::variant that I'd like to convert to another std::variant that has a super-set of its types. Is there a way of doing it than that allows me to simply assign one to the other?
template <typename ToVariant, typename FromVariant>
ToVariant ConvertVariant(const FromVariant& from) {
ToVariant to = std::visit([](auto&& arg) -> ToVariant {return arg ; }, from);
return to;
}
int main()
{
std::variant<int , double> a;
a = 5;
std::variant <std::string, double, int> b;
b = ConvertVariant<decltype(b),decltype(a)>(a);
return 0;
}
I'd like to be able to simply write b = a in order to do the conversion rather than going through this complex casting setup. Without polluting the std namespace.
Edit: Simply writing b = a gives the following error:
error C2679: binary '=': no operator found which takes a right-hand operand of type 'std::variant<int,double>' (or there is no acceptable conversion)
note: while trying to match the argument list '(std::variant<std::string,int,double>, std::variant<int,double>)'
This is an implementation of Yakk's second option:
template <class... Args>
struct variant_cast_proxy
{
std::variant<Args...> v;
template <class... ToArgs>
operator std::variant<ToArgs...>() const
{
return std::visit([](auto&& arg) -> std::variant<ToArgs...> { return arg ; },
v);
}
};
template <class... Args>
auto variant_cast(const std::variant<Args...>& v) -> variant_cast_proxy<Args...>
{
return {v};
}
You might want to fine tune it for forwarding semantics.
And as you can see its use is simple:
std::variant<int, char> v1 = 24;
std::variant<int, char, bool> v2;
v2 = variant_cast(v1);
Options:
Write your own variant type, possibly inheriting from std::variant, that implements operator= and construction the way you want. Some work has to be done, because variant's constructors can do SFINAE tricks that might not work properly with your variant type; to that end, you want to do some SFINAE forwarding to base-variant yourself instead of naked using declarations.
Write a better ConvertVariant that doesn't require the source/destination types to be listed. You would return a convert helper template type that holds the source variant which has an operator std::variant<Ts...>()&& that calls something very much like your ConvertVariant.
I want to refer to function pointers of built-in operators, but I don't know how to specify the specific type overloads.
I have the following template class signature:
template<typename ParamsType, typename FnCompareType>
class MyAction
{
public:
MyAction(ParamsType& arg0, ParamsType& arg1, FnCompareType& fnCpmpare)
: arg0_(arg0), arg1_(arg1), fnCompare_(fnCpmpare) {}
bool operator()()
{
if((*fnCompare_)(arg0_,arg1_)
{
// do this
}
else
{
// do s.th. else
}
}
private:
ParamsType& arg0_;
ParamsType& arg1_;
FnCompareType& fnCompare_;
}
And want to use a syntax like this:
void doConditional(int param1, int param2)
{
MyAction<int,&::operator>=> action(param1,param2);
if(action())
{
// Do this
}
else
{
// Do that
}
}
But that doesn't compile:
error: ‘::operator>=’ has not been declared
What can I do to refer to such intrinsic static operations?
Built-in operators
Why you cannot have function pointers of them:
C++11, §13.6/1, [over.built]
The candidate operator functions that represent the built-in operators defined in Clause 5 are specified in this subclause. These candidate functions participate in the operator overload resolution process as described in 13.3.1.2 and are used for no other purpose.
Built-in operators (those for the built-in types) aren't real operator functions. So you can't have function pointer pointing to them. You also cannot invoke them using operator<(A,B) syntax.
They only participate in overload resolution but the compiler will translate them directly into the appropriate asm/machine instruction without any kind of "function call".
The way to get around this issue:
user1034749 has already answered this question, but for completeness:
The standard defines a lot of function objects in §20.8, [function.objects], i.e.
Arithmetic operations
Comparisons
Logic operations
Bitwise operations
A function object is an object of a function object type. In the places where one would expect to pass a pointer to a function to an algorithmic template (Clause 25), the interface is specified to accept a function object. This not only makes algorithmic templates work with pointers to functions, but also enables them to work with arbitrary function objects.
C++11, §20.8.5, [comparisons]
equal_to
not_equal_to
greater, less
greater_equal
less_equal
Those are templated function objects which decay to the analogous operator in their operator() function. They can be used as function pointer arguments.
user1034749 is right, I want to state: There's no other way, these are completely equivalent in usage to 'raw' function pointers. Reference given.
Standard class type operators
You can use standard library operators as function pointers (which are present as "real functions").
But you'll have to refer to the respective instance of the template. The compiler will need appropriate hints to deduce the correct template.
This works for me on MSVC 2012 using operator+ of std::basic_string
template<class Test>
Test test_function (Test const &a, Test const &b, Test (*FPtr)(Test const &, Test const &))
{
return FPtr(a, b);
}
int main(int argc, char* argv[])
{
typedef std::char_traits<char> traits_t;
typedef std::allocator<char> alloc_t;
std::basic_string<char, traits_t, alloc_t> a("test"), b("test2");
std::cout << test_function<std::basic_string<char, traits_t, alloc_t>>(a, b, &std::operator+) << std::endl;
return 0;
}
If the template argument of test_function is left out to be deduced this will fail (at least for MSVC 2012).
You can use the same solution as used in C++ standard library:
std::sort (numbers, numbers+5, std::greater<int>());
where greater is
template <class T> struct greater : binary_function <T,T,bool> {
bool operator() (const T& x, const T& y) const {return x>y;}
};
in your case http://www.cplusplus.com/reference/functional/greater_equal/
About reference of built operator.
You can reference existing operator< for any class (of course if they are not private, protected or your class/function not friend).
But opeator< for builtin types (bool, short, int, double) it is not possible reference.
Event if not look at C++ standard you can see from my text above.
An extension to the solution provided by fghj, that would work for assignment type operators, such as +=/-=, etc would be to wrap these similarly to the standard variants. You could then do:
#include <iostream>
template <typename T>
struct assign_plus {
void operator() const (T& a, const T& b){
a += b;
}
};
template <typename T>
struct assign_minus {
void operator() const (T& a, const T& b){
a -= b;
}
};
template<template <class T> class O> requires requires(int& a, const int& b){
{ O<int>{}(a,b) };
}
void example(int& a, const int& b){
O<int>{}(a,b);
}
int main(){
int a = 5;
int b = 6;
example<assign_plus>(a,b);
std::cout << a << "\n";
example<assign_minus>(a,b);
std::cout << a << "\n";
return 0;
}
where the constraint could be kept/removed given c++20 compatibility. These constraints then also could be extended to require that a += b is valid (for custom types for example).