Compilation error about operator reloading using boost::variant - c++

I'am trying to learn boost.variant. However, the code which I copied from a book won't pass the compilation:
class var_print : public boost::static_visitor<void>
{
public:
template<typename T>
void operator()(T &i) {
i *= 2;
cout<<i<<endl;
}
};
Here is how I tried to use it.
typedef boost::variant<int,double,string> var_t;
var_t v(1); //v->int
boost::apply_visitor(var_print(),v);
The compiler generates the following error:
ERROR:no match for 'operator*=' in 'i *= 2'
That puzzles me,since template function will determine the type of parameter whenever it's called and int should defined the operator *=.

You need to have a separate operator() for std::string& since no operator *= is defined for std::string.
In addition, your operator must be marked const since you are passing a temporar visitor instance to apply_visitor.

Related

Overloading specialized assignment operator based on typename

Okay, the title is a mouthful and hopefully specific enough, but I'm running into a C++ issue which I think is possible, I just can't seem to find the proper syntax.
I have a simple template-based property class:
template <typename T>
class Property
{
public:
Property<T> &operator = (const T &src)
{
m_data = src;
return *this;
};
operator const T& () const
{
return m_data;
}
private:
T m_data;
};
I need to assign values from a QVariant, which is also sort of a property but without templates. At the moment I am deferencering the values explicitly when assigning:
Property<QString> p1;
Property<int> p2;
p1 = var1.toString();
p2 = var2.toInt();
This works but it is tedious and I'm sure the compiler can do the work for me. So, I tried implementing specialized assignment operators based on the typename of the Property; in other words, if the template specialization is based on a QString use one function, if it is based on an int use another function, et cetera.
I tried things like:
Property<QString> &operator = (const QVariant &ref)
{
m_data = ref.toString ();
return *this;
};
or...
template <typename int> &Property<int>::operator = (const QVariant &ref)
{
m_data = ref.toInt ();
return *this;
};
or...
template<> Property<T> &Property<QString>::operator = (const QVariant &ref)
{
m_data = ref.toString ();
return *this;
}
..both inside and outside of the class declaration but to no avail. I get errors like "expected nested-name-specifiers", "two or more data types in declaration of parameters" and the like.
Any pointers to the correct syntax would be appreciated!
PS: the first declaration compiles witout error, but adding the same declaration for <int> makes it ambiguous since only the return type differs.
Compiler is GCC 4.8.2 with --stdc=c++11 enabled.
Although the answer of paddy seems correct, it seems to me tedious to generalize it (implement a specialzed assignment operator to all the types that a QVariant can hold, in addition to QString and int).
An easier solution would be to specialize the assignment operator once for all, in a way that benefits from the built-in conversions that the QVariant provides:
Property& operator= (const QVariant& src)
{
assert(src.canConvert<T>());
m_data = src.value<T>();
return *this;
}
The original class definition is a bit wrong, as pointed out by Kirill Kobelev in your question's comments section. Now, let's fix that and also add another operator=:
template <typename T>
class Property
{
public:
Property & operator=( const T & src )
{
m_data = src;
return *this;
}
// This one must be specialized
Property & operator=( const QVariant & src );
const T & operator() const
{
return m_data;
}
private:
T m_data;
};
The specialization is therefore quite simple. Here's ones for QString and int:
template <>
Property<QString> &
Property<QString>::operator=( const QVariant & src )
{
return operator=( src.toString() );
}
template <>
Property<int> &
Property<int>::operator=( const QVariant & src )
{
return operator=( src.toInt() );
}
Now you are free to assign QVariant values directly to any Property which provides that specialization. If you try to do it on a class that did not specialize then you will get an error.
I don't have the reputation to comment, nor the expertise to claim insight so please don't take this as an "answer".
But your question reminded me of a lesson on Cpp, Overloads and Functions over at http://www.cplusplus.com/doc/tutorial/functions2/ .
Excerpt:
"In the example above, we used the function template sum twice. The first time with arguments of type int, and the second one with arguments of type double. The compiler has instantiated and then called each time the appropriate version of the function.
Therefore, result will be a variable of the same type as the parameters a and b, and as the type returned by the function.
In this specific case where the generic type T is used as a parameter for sum, the compiler is even able to deduce the data type automatically without having to explicitly specify it within angle brackets."
Apologies if I missed the point, but thought this may help.

Call of explicitly instantiated template function through conversion operator

Let us assume we have a function template which is implemented in the cpp file with help of explicit instantiation like this:
function.h
template<typename T> void function(T val);
function.cpp
#include "function.h"
template<typename T> void function(T val) { /* do something */ }
template void function<double>(double val);
We are now able to call the function in a main file that includes function.h like this:
double val = 1.0;
function(val);
Let us further assume we have a class which is implemented like this:
data.h
class Data
{
private:
double mVal;
public:
Data(double val) { mVal = val; }
operator double () { return mVal; }
};
The following code results in the linker error LNK2019: unresolved external (Visual Studio 2010):
Data a(1.0);
function(a);
We could use one of the following expressions to supply a to function()
function<double>(a);
function(double(a));
...
but why is it not possible to just call function(a)? Does there exist any other solution to achieve that without explicitly instantiating function() with type Data?
why is it not possible to just call function(a)?
It is. You're calling it. But remember that function is declared as:
template<typename T> void function(T val);
so template deduction will deduce function<Data>. The template deduction doesn't know that elsewhere in the code you only have a definition for function<double> - it just does deduction. And function<Data> doesn't have a definition, so it fails to link.
Performing the explicit cast yourself (either function<double>(a) or function(static_cast<double>(a))) would be the best solution in my opinion. Explicit is nice. You could additionally write a separate function with all the overloads you actually support and just forward to the function template:
void fwd_function(double v) { function(v); }
void fwd_function(foo v) { function(v); }
void fwd_function(bar v) { function(v); }
fwd_function(a); // now we call function<double> because fwd_function(double )
// is the what we're actually calling
It is not possible to call function(a), because then T will be of type Data, and not double, even though it has that conversion operator. And because you are not explicitly defining it in the cpp file, you get a linker error.
Here are some solutions you could use:
//Call operator double() explicitly
function(a.operator double());
//Specify T
function<double>(a);
//Casting
function(static_cast<double>(a));

Overloading operator T***()

I don't know, why my code doesn't work. I create struct and inside put overloading operatoroperator T***(), In main I'd like using following notation const int * const * const * p1 = a;
struct A{
template<class T> operator T***(){}
};
int main(){
A a;
const int * const * const * p1 = a;
return 0;
}
Error: undefined reference to '_ZN1AcvPPPT_IKiEEv'
You simply missed to give your type conversion function an implementation
struct A{
template<class T> operator T***() {
return nullptr; // Do whatever you want to do here.
}
};
See a working sample please.
I have absolutely no idea what you are trying to do, but your problem is a linker problem. You just declare (but not define) the conversion operator T***. You have to define it,
template<class T> operator T***()
{
// define it here
}
Before you edited the question:
template<class T> operator T***();
declares the operator template, but doesn't define it, hence the error that it's undefined. You'll get that error even if you define the template in another source file, since templates must be defined in every translation unit that uses them.
After the edit:
template<class T> operator T***(){}
the code compiles, but has undefined behaviour since the operator is missing a return statement.

compilation error: overloading operator()

VisualStudio 2008 (VC++ 9)
Problem with overloading operator()
Hello community!
It seems that overloaded version of operator() must all differ in their argument list, independly of the return type.
I have the following case:
class Sha256{
public:
QVector<quint32> operator()(QString const& data);
QByteArray operator()(QByteArray const& data);
QVector<quint32> operator()(QByteArray const& data); // this is line 168
...
}
Last declaration leads to following compilation error:
.\sha256.cpp(168) : error C2556: 'QVector Sha256::operator ()(const QByteArray &)' : overloaded function differs only by return type from 'QByteArray Sha256::operator ()(const QByteArray &)'
with
[
T=uint
]
On the other side, following declarations are working:
class Sha256{
public:
QVector<quint32> operator()(QString const& data);
QByteArray operator()(QByteArray const& data);
...
}
because they have different arguments.
One way would be to add in the first case an additional argument like
QByteArray<quint32> operator()(QByteArray const& data, bool getByteArray)
but this is embarassing, not intuitive and also not clean (return type would be a QByteArray, independly of the value of getByteArray, even in case of false!).
Another way could be to use a template function like
template<class T> T operator()(QByteArray const& ba)
template<class T> T operator()(QString const& str)
but T could only be of a few 'supported' type (QByteArray and QVector), therefore user could run into trouble if using wrong T Type. This version seems to be error prone.
So my questions are:
1. Why is the return type of function objects not taken into account in the signature to distinguish between different flavors of the function like in 'classical' functions?
2. Is there a better way around than adding an additional dummy argument?
Thank you for your valuable time.
Alain
Return type is never used for overload resolution. In fact, you can't even declare two functions that differ only in return type. In my opinion, adding this feature would be complicated and not that helpful. Is it necessary to use the function call operator? You could just use a named member function, and then give them different names. Another option would be to use a member template, but even then you would need to explicitly give the return type as a template argument, and the syntax would be ugly if done on the function call operator.
The comment from Kerrek SB suggests a workaround by leveraging conversion operators, if you are okay with something that is complex on the inside, but simpler on the outside.
#include <iostream>
struct A {};
struct B {};
A fooA_impl(const char *) {
std::cerr << "A impl" << std::endl;
return A();
}
B fooB_impl(const char *) {
std::cerr << "B impl" << std::endl;
return B();
}
class Helper {
public:
operator A() { return fooA_impl(p); }
operator B() { return fooB_impl(p); }
private:
friend Helper foo(const char *p);
Helper(const char *p_) : p(p_) {}
const char *const p;
};
Helper foo(const char *p) {
return Helper(p);
}
int
main() {
A a(foo("hello"));
B b(foo("hello"));
}
You can't use overload by return type. One thing you can do is to add the return type as a tag parameter when overloading operator():
QByteArray operator()(QByteArray const& data, const QByteArray& tag );
QVector<quint32> operator()(QByteArray const& data, const QVector<quint32>& tag);
The below is how you call these function:(assume both types have default constructors).
(data, QByteArray());
(data, QVector<quint32>());

type casting problem with template class in C++

I am not a template or type casting expert, so I really need some help.
I have to use an existing template class and encounter the following type cast problem.
I put some sample code to illustrtrate the problem.
//template class definition
template <class IntType>
class CUSTOMIZE_Int: public CUSTOMIZE_Type
{
public:
operator const IntType() const;
private:
IntType m_int;
}
template<class IntType>
CUSTOMIZE_Int<IntType>::operator const IntType() const
{
return m_int;
}
// the template class instantiation
typedef CUSTOMIZE_Int<WRAPPER_Int32> CUSTOMIZE_UnsignedInt;
Then in my code, I derive a new class
// the derived class definition
class IntNum: public CUSTOMIZE_UnsignedInt
{
// ctors and new methods;
}
and creat a variable, and try to make the conversion to get the data.
class IntNum& i;
const WRAPPER_Int32 j = i;
with the following compile error:
error: cannot convert "IntNum" to "const WRAPPER_Int32" in initialization.
What is the right way to do the conversion, or what is the problem with my code?
Thanks for any comments!
I guess that you expect operator IntType()
class ...
operator const IntType() const;
}
to act here, when you assign i to j:
const WRAPPER_Int32 j = i;
However, this is not an implicit conversion, you must do it explicitely:
const WRAPPER_Int32 j = (WRAPPER_Int32) i;
Hope this helps.