Say I have the following struct:
struct Parameter {
double value;
double error;
};
So that I'm usually working with vectors of that struct (ie. std::vector<Parameter>), and ocasionally I want to set a vector of values (but not errors) in that vector of parameters by using the operator= with a standard std::vector, for convenience.
std::vector<Parameter> vector_of_parameters;
std::vector<double> vector_of values;
....
vector_of_parameters = vector_of_values;
To do so, I'm trying to overload operator= for this struct as follows:
std::vector<Parameter> operator=(const std::vector<double>& v) {
this->clear();
for (const auto& i:v) {
Parameter p;
p.value = i;
this->push_back(p);
}
return *this;
}
But this will return an error saying that std::vector operator=(const std::vector& v) must be a non-static member. So if I understand it correctly, I have to define this as a member function of the operator as:
std::vector<Parameter>::operator=(const std::vector<double>& v) {
this->clear();
for (const auto& i:v) {
Parameter p;
p.value = i;
this->push_back(p);
}
return *this;
}
The error now says that a syntaxis with template<>, but I dont really see it, or understand it, and don't know what more can I do.
You cannot overload the assignment operator of std::vector. operator = must be a member function and you just can't add a member function to std::vector.
What you can do is make a convenience function like create_parameters that takes a std::vector<double> and returns a std::vector<Parameter>. That would look like
std::vector<Parameter> create_parameters(std::vector<double> const& params)
{
std::vector<Parameter> ret(params.size());
std::transform(params.begin(), params.end(), ret.begin(),
[](auto value) { return Parameter{value, 0}; });
return ret;
}
and then
vector_of_parameters = vector_of_values;
would become
vector_of_parameters = create_parameters(vector_of_values);
I think that an alternative simple way to create std::vector<Parameter> from std::vector<double> is defining a single argument constructor Parameter(double value) which accepts the Parameter::value:
#include <vector>
#include <optional>
struct Parameter
{
double value;
std::optional<double> error;
explicit Parameter(double v) : value(v)
{}
};
Then you can use range-constructor as follows:
DEMO
std::vector<Parameter> v_of_parameters(v_of_values.cbegin(), v_of_values.cend());
Related
Using functors with parameters generally looks like that:
// Definition:
struct some_functor_with_params
{
int ref;
explicit some_functor_with_params(int ref) : ref(ref) {}
bool operator ()(int i) const {return i == ref;}
};
// Usage:
std::vector<int> v;
std::find_if(v.begin(), v.end(), some_functor_with_params(42));
For a functor without parameters, the code may become
// Definition:
struct some_functor_without_params
{
bool operator ()(int i) const {return i == 42;}
};
// Usage:
std::vector<int> v;
std::find_if(v.begin(), v.end(), some_functor_without_params());
but I would prefer the following usage:
std::vector<int> v;
std::find_if(v.begin(), v.end(), some_functor_without_params); // no parens
which has the following advantages:
more concise
more readable when invoking the functor directly: some_functor_without_params(i) rather than some_functor_without_params()(i)
interchangeable with a function: bool some_functor_with_params(int i) {return i == 42;}
I implemented it the following way in a header file:
namespace {
struct
{
bool operator ()(int i) const {return i == 42;}
} some_functor_without_params;
}
I think the struct does not need a name since it has no user-declared constructor (nor destructor, nor anything requiring the struct name). I put the object in an unnamed namespace so that each compilation unit has its own some_functor_without_params and there is no 'double definition' link error.
Is there any performance penalty or any other drawback I cannot see?
This approach worked as expected until I encountered a very strange compilation error with Visual C++ 2013 which disappeared when naming the functor type, i.e. replacing
struct
{
bool operator ()(int i) const {return i == 42;}
} some_functor_without_params;
with
struct some_functor_without_params_t
{
bool operator ()(int i) const {return i == 42;}
} some_functor_without_params;
The error occurs only in Debug, not in Release, and states
error C2039: '<unnamed-type-some_functor_without_param>': is not a member of 'my_namespace:: ?? A0xbf2cc73f'
in file xstring, here:
_Myt& operator+=(const _Elem *_Ptr)
{ // append [_Ptr, <null>) // <-- on this line(!)
return (append(_Ptr));
}
It looks like a compiler bug, what do you think?
I am a bit perplexed. I am creating a custom "Variant" class, but am running into a strange issue with std::string member.
When I try to assign it from another Variant instance, I get an exception that the string is a bad pointer. I am not sure I understand why this would happen because the string should be an instance when the class is constructed.
Here is my code:
class Variant : ObjectBase {
public:
Variant() {};
Variant(const Value& node) { parse(node); };
ValueType Type = ValueType::Unknown;
Variant& operator= (bool value)
{ Type = ValueType::Boolean; value_.vBool = value; return *this; };
Variant& operator= (std::string value)
{ Type = ValueType::String; value_string_ = value; return *this; };
Variant& operator= (double value)
{ Type = ValueType::Double; value_.vDouble = value; return *this; };
Variant& operator= (int32_t value)
{ Type = ValueType::Int32; value_.vInt32 = value; return *this; };
Variant& operator= (int64_t value)
{ Type = ValueType::Int64; value_.vInt64 = value; return *this; };
Variant& operator= (uint32_t value)
{ Type = ValueType::Uint32; value_.vUint32 = value; return *this; };
Variant& operator= (uint64_t value)
{ Type = ValueType::Uint64; value_.vUint64 = value; return *this; };
Variant& operator= (const Value& node) { parse(node); };
private:
union Any {
int32_t vInt32;
int64_t vInt64;
double vDouble;
bool vBool;
uint32_t vUint32;
uint64_t vUint64;
Any() : vDouble(0) {};
} value_;
std::string value_string_;
};
The exception occurs when I do this:
Variant v1 = "Hello";
Variant v2 = v1; // <--- Here is where it occurs
Now, if I create a manual = operator overload, I can see that v2 value is a bad pointer, but I am not sure why. Here is my overload:
Variant& operator= (const Variant value) {
value_ = value.value_;
value_string_ = value.value_string_;
Type = value.Type;
return *this;
}
Maybe I am tired or something, but it is not obvious to me what am I missing here.
Assuming this code compiles at all (which is not clear, as complete code has not been given) then the statements
Variant v1 = "Hello";
Variant v2 = v1;
invoke constructors, not assignment operators.
In the first, since Variant does not supply a constructor that accepts a string, this means Value does, and an implicit conversion to Value is being done before invoking the constructor for Variant. The problem is therefore either in the constructor for Value, or in working of the parse()` function. Neither of those have been shown though.
The second statement invokes the compiler-generated copy constructor. Which, if the preceding construction has not worked as required, will also introduce problems.
I am trying to use std::equal_range with the structure below I have compilation error saying that error: no match for ‘operator<’ .
struct MyFoo {
int v_;
string n_;
bool operator<(int v) const
{ return v_ < v;}
};
vector<MyFoo> data;
// data is sorted by int v_
typedef vector<MyFoo>::iterator Ptr;
std::pair< Ptr, Ptr > pr = std::equal_range(data.begin(), data.end(), 10);
I've looked into the template implementatino and what is failing is the following where *it is deferenging the iterator pointing to an object of MyFoo and val_ is 10.
if(*it < val_) {
...
}
Why it is not working? I thought probably because it is trying to call the the global operator< that is not defined, but since I defined it as class member that should not be a problem, isn't it?
Provide non-member comparison operators :
bool operator<(int v, const MyFoo& foo)
{
return foo.v_ < v;
}
bool operator<(const MyFoo& foo, int v)
{
return v < foo;
}
Alternatively, you can provide a conversion operator to int :
operator int() cont {return v_;}
Which is probably unwanted, since the compiler will be able to perform silent conversions in other places of your code.
As an other alternative: provide
bool operator<(const MyFoo& rhs) const { return v_ < rhs.v_; }
And use std::equal_range on a dummy object with correct v_ as:
std::pair<Ptr, Ptr> pr = std::equal_range(data.begin(), data.end(), MyFoo{10, ""});
You may be having trouble because the std::equal_range implementation uses std::less. This is going to try to convert your MyFoo to an int to do the comparison, rather than just using an operator<() overload. Try adding this to your MyFoo class...
operator int() const
{
return v_;
}
I have a vector v containing objects of type structure say A. Now I need to find the iterator for a particular object stored in this vector. e.g:
struct a
{
};
vector<a> v;
struct temp; //initialized
Now if I will use
find(v.begin(),v.end(), temp);
then compiler generates error saying no match for operator '=='.
Any workaround for getting an iterator corresponding to an object in a vector?
You have to provide either a bool operator==(const a& lhs, const a& rhs) equality operator for your class, or pass a comparison functor to std::find_if:
struct FindHelper
{
FindHelper(const a& elem) : elem_(elem) {}
bool operator()(const a& obj) const
{
// implement equality logic here using elem_ and obj
}
const a& elem_;
};
vector<a> v;
a temp;
auto it = std::find_if(v.begin(), v.end(), FindHelper(temp));
Alternatively, in c++11 you can use a lambda function instead of the functor.
auto it = std::find_if(v.begin(), v.end(),
[&temp](const a& elem) { /* implement logic here */ });
Here's a simplified version of my problem. I have a property class. It has data like has_initalized and such which i removed for this example.
When i call a function which uses T its fine. However T& isnt so i decided to write a T& version of it. But this causes all functions which uses plain T to get a compile error. Why is T& interfering with that? For this example how do i get both functions (Q and W) to work without changing main()?
template <class T>
class Property {
T v;
Property(Property&p) { }
public:
Property() {}
T operator=(T src) { v = src; return v; }
operator T() const { return v; }
operator T&() const{ return v; }
T operator->() { return v; }
};
class A{};
void Q(A s){}
void W(A& s){}
int main(){
Property<A> a;
Q(a);
W(a);
}
There is nothing in the overloading rules of C++ which allows the compiler to choose between operatorT() and operatorT&() in the call to Q. So removing the
operator T() const { return v; }
will also remove the ambiguity. But then you'll have a problem because returning a non const reference to a member in a const function is not possible.
For your Q, you can use both conversion functions. You can make the compiler prefer one over the other by making one non-const.
operator T() const { return v; }
operator T&() { return v; }
Now for Q, the operator T& is taken. This way will also fix the call to W to get a non-const reference. You can also return a const reference from the other
operator T const&() const { return v; }
operator T&() { return v; }
This way will still prefer the second conversion function for Q, but if your object a is const and you initialize a const reference, you won't always require to copy v.