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).
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 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).
I'm trying to override the << operator but it seems that the compiler doesn't recognize my implementation and instead tries to interpret it as a bit shift.
I've already tried to play around with the parameter types (const T&, T&, T, const T) to no avail.
#pragma once
template<typename T> class AbstractStack
{
public:
virtual bool Push(const T &) = 0;
}
template <typename T> class ArrayStack : public AbstractStack <T>
{
public:
bool Push(const T&) {
....
}
}
template <typename T> bool operator<<(const AbstractStack<T>* &, const T&) {
return stack->Push(item);
}
int main() {
AbstractStack<int> *stack = new ArrayStack<int>(5);
int a = 2;
stack << a; // <<-- compiler error
return 0;
}
The error reported is:
Error (active) expression must have integral or unscoped enum type Lab10
Error C2296 '<<': illegal, left operand has type 'AbstractStack<int> *'
If I define the same operator acting on the class as a value, it just works...
When overloading operators, at least one of the arguments must be a class or an enum type - basically this allows/limits you to overloading custom types (user defined types).
From the cppreference;
When an operator appears in an expression, and at least one of its operands has a class type or an enumeration type, then overload resolution is used to determine the user-defined function to be called among all the functions whose signatures match the following...
This makes sense in that it disallows you from overloading the built in types; in this case, the pointer and integer you have as arguments.
As you already remarked in the question, the solution is taking your first argument by reference;
template <typename T>
bool operator<<(AbstractStack<T> &, const T&)
{ //...
Given the abstract base class you are looking to use, you could investigate the use of std::shared_ptr to help manage the resources and make the use of a "pointer" in the overloaded operator (albeit it will be a smart pointer);
template <typename T>
bool operator<<(std::shared_ptr<AbstractStack<T>>&, const T&)
{
return stack->Push(item);
}
int main() {
std::shared_ptr<AbstractStack<int>> stack = std::make_shared<ArrayStack<int>>(5);
int a = 2;
stack << a;
return 0;
}
As others have said, overloading any builtin operator requires an object of a user-defined type; a pointer won't work. And the solution is to use an object instead of a pointer:
template <typename T> bool operator<<(AbstractStack<T>&, const T&) {
return stack.Push(item);
}
and then call it with an object. There's no good reason in the code you've shown to allocate from the free-store; just create an auto object:
int main() {
ArrayStack<int> stack(5);
int a = 2;
stack << a;
return 0;
}
I have two variables and an operator (could be any of +, - , /, comparison...).
Is it a good idea to write a function that takes 2 arguments and the operator as the parameters?
Function may be something like below
T foo(int a,int b, sometype(not sure) operator)
and then make a string out of that
foo(a,b,+);
as a+b
Would this be a good approach or is there any other approach?
You can't. Operators are special, they are not ordinary functions. (For instance, operators can have short circuit evaluation and have no overload resolution if all operands are built-in types. Functions cannot do that.)
Pass a binary operation object instead, like:
template <class BinaryOp>
int fun(int, int, BinaryOP);
You can then pass functors like an instance of std::plus<> or binary lambdas† as a third argument. This is a common practice in C++.
Note that functors wrapping the built in operators, such as the aforementioned std::plus, are readily available in the header <functional>.
Sample code for reference:
#include <iostream>
#include <functional>
template <class T>
void fun (int i, int j, T t) {
std::cout << t(i,j) << "\n";
}
int main () {
fun(1,2,std::plus<>{}); // Or std::plus<int>{} in C++11
fun(1,2,[](auto i, auto j){return i * j;}); // Again, with explicit types for C++11
}
This will print
3
2
†As this is tagged C++11: The functors std::plus<T=void> etc. as used in this answer are available in C++14 and later. In C++11, you need to provide a template argument like std::plus<int>. Same goes for the lambda, which would need to become [](int i, int j){...}.
Operators cannot be passed that way, it wouldn't compile: the languages doesn't allow that. You could pass a character that describes the operation to do:
template <class T>
T foo(T lhs, T rhs, char op)
{
switch (op)
{
case '+':
return lhs + rhs;
// other operators
}
}
Another option is passing a function that does the actual computation as parameter:
template <class T, class Operator>
T foo(T lhs, T rhs, Operator op)
{
return op(lhs, rhs);
}
Now you can write your Operators or use the ones already provided: std::plus, std::minus etc. You find them in <functional>.
// ...
foo(5, 10, std::plus<int>{})
If you want to have your versions of these, write the required callables as lambdas or functions:
template <class T>
T add(T lhs, T rhs) { return lhs + rhs; }
foo(5, 10, add<int>);
foo(5, 10, [](int a, int b){ return a + b; }); // or use `auto` to make it generic
Why wouldn't the following compile:
void f(int8_t a)
{
}
void f(int16_t a)
{
}
typedef boost::variant<int8_t, int16_t> AttrValue;
int main()
{
AttrValue a;
a = int8_t(1);
f(a);
}
With the compiler error:
error C2665: 'f' : none of the 2 overloads could convert all the argument types
could be 'void f(int8_t)'
or 'void f(int16_t)'
However, this is OK:
std::cout << a; // f(a);
Where is Where is std::ostream &operator<<(std::ostream &, const AttrValue &) defined and why is it defined?
Overload resolution happens at compile time, when your boost::variant instance could contain either type, so the compiler has no way of knowing whether to call void f(int8_t) or void f(int16_t).
std::cout << a works because in either case it's calling the same function, std::ostream &operator<<(std::ostream &, const AttrValue &), which inside dispatches on the runtime type of the instance.
You need to write a visitor to perform the dispatching:
struct f_visitor: public boost::static_visitor<void>
{
template<typename T> void operator()(T t) const { return f(t); }
};
boost::apply_visitor(f_visitor(), a);
Well, for one thing you are assigning a to itself. And since none of the overloads take a boost::variant type then of course the compiler can't find the correct function.
Also, you may have to use boost::get to get value:
f(boost::get<int8_t>(a));
It happens that operator<< is defined for boost::variant, so the compiler does not need to perform any implicit type conversion. For your f() function, on the other hand, it does not know which conversion to select.