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.
Related
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 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).
Motivation
Suppose that I have a function taking void * as an argument. I'd like to overload this function to other pointer types, but disable the implicit conversion from other pointer types to void * (and only that conversion). I still want the implicit conversion to base class types to succeed.
class Base {};
class Derived : public Base {};
class Other {};
class Stream {};
Stream & operator<<(Stream&, void *);
Stream & operator<<(Stream&, const Base*);
void test() {
Stream str;
Derived der;
Other other;
// I want the below to work
str << (void*)&der;
str << &der; // (&der) gets implicitly converted to const Base*
// But I want this to fail at either compile or link time
str << &other;
}
The Pedantic Pointer Idiom
Prevention of implicit conversion to pointer-to-void has been called a Pedantic Pointer Idiom by Matt Wilson, and it's useful when implementing type-safe streams and logging.
His implementation uses a template facade that dispatches to am implementation with a dummy pointer-to-pointer argument. This leverages the fact that Foo** is not implicitly convertible to void**. I'd like to avoid the overhead of the second argument.
template <typename T> Stream & operator<<(Stream & s, T const* t)
{
return dump(s, t, &t);
}
One way of solving it is to specialize the operator for the void type. That way there's no need to declare Stream & dump(Stream &, void const*), thus side-stepping the problem.
template <typename T> Stream & operator<<(Stream & s, T const* t)
{
return dump(s, t);
}
template <> Stream & operator<<(Stream & s, void const * t)
{
// implement the dump here
return s;
}
int x = fromString("test") :could not deduce template argument for 'ValueType'
int x = fromString<int>("test") : works fine as expected
So why does the compiler struggle here? I see it with all kinds of real template functions, not just this silly example. It must be a feature of the language, but what?
You can't deduce based on the return type. You can, however, implement a workaround with similar syntax, using the overloaded cast operator:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class FromString{
private:
string m_data;
public:
FromString(const char*data) : m_data(data) {}
template<typename T>
operator T(){
T t;
stringstream ss(m_data);
ss >> t;
return t;
}
};
template<> FromString::operator bool(){
return (m_data!="false"); //stupid example
}
int main(){
int ans = FromString("42");
bool t = FromString("true");
bool f = FromString("false");
cout << ans << " " << t << " " << f << endl;
return 0;
}
Output:
42 1 0
C++ doesn't do type inference on the return value. I.e., the fact that it is being assigned to an int isn't used in template parameter deduction.
(Removed edit, since someone else presented the overloaded cast solution already.)
Besides the bad choice for an example (probably makes sense to have int x = to<int>("1235") rather than toString), the problem is that the return type does not participate in overload resolution or type inference[1]. The reason for this is that the expression can be used in many places where the type of the return cannot be deduced:
// assuming template <typename T> T to( std::string ):
//
f( to("123") ); // where there are two overloads f(int), f(double)
int x = 1.5 * to("123"); // T == int? T == double?
to("123"); // now what? returned object can be ignored!
So the decision is that the return type will not take part in overload resolution or type deduction.
[1] There is a single exception to this rule, which is the evaluation of a function pointer with more than one overload, where the overload must be selected by either the destination pointer or an explicit cast, but this is just the one exception and is not used in any other context:
void f();
void f(int);
void g( void (*)() );
void g( void (*)(int) );
void (*p1)() = &f; // overload selected based on destination type
void (*p2)(int) = &f;
g( (void (*)(int))&f ); // overload selected based on explicit cast
It looks like your template has the return type templated which cannot be automatically deduced which is why you need to add it in here.
The return type of a function is dependent on overload resolution, not the other way around.
There is a trick that works though: operator= usually exists only for equal LHS/RHS argument types, except when an explicit operator= is defined (whether as standalone or as a member does not matter).
Thus, overload resolution will find operator=(int &, int), and see if the return value from your function is convertible to int. If you return a temporary that has an operator int, this is an acceptable resolution (even if the operator int is in the generic form of a template<typename T> operator T).
Thus:
template<typename T, typename U>
U convert_impl(T const &t);
template<typename T>
struct convert_result {
convert_result(T const &t) : t(t) { }
template<typename U> operator U(void) const { return convert_impl<U>(t); }
T const &t;
};
template<typename T>
convert_result<T> convert(T const &t) { return t; }