jeudi 26 février 2015

how to distinguish functions for elements and objects in c++

This looks to me like a basic problem so apologies in advance for duplicate posts. Not sure what the terminology is though.


I have a class, say my_data, for storing numbers. It has the basic constructors etc. and it would be handy to support elementary operations such as adding to the elements, e.g. increasing the values in the data.


This is the most elementary way to describe the class:



#include <stdlib.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <numeric>
#include <iterator>

template <typename T>

class my_data {

public:
my_data (const my_data& other);
my_data& operator=(const my_data& rhs);
my_data (const size_t bsize) { my_datavec.resize(bsize); }
my_data (std::vector<T> init) { my_datavec = init; }

template <typename U>
void add(const U addition) {
std::transform(my_datavec.begin(), my_datavec.end(),
my_datavec.begin(),
bind2nd(std::plus<T>(), addition) );
}

template <typename U>
void add(const my_data<U> addition) {
std::transform(my_datavec.begin(), my_datavec.end(),
addition.my_datavec.begin(),
my_datavec.begin(),
bind2nd(std::plus<T>(), addition) );
}

void print() {
std::ostream_iterator<T> out_it (std::cout,", ");
std::copy(my_datavec.begin(), my_datavec.end(), out_it);
}

protected:
std::vector<T> my_datavec;

};

int main() {

std::vector<int> int_test({1,2,3});
my_data<int> a(int_test);

a.add(2);
a.print();

a.add(a);
a.print();

return(0);

}


The problem starts when I want to add the values of one object to the values of another (abusing the fact here that they are the same size to omit checks):



$ g++ -std=c++11 template2.cpp -o template2
In file included from /usr/include/c++/4.7/bits/stl_function.h:741:0,
from /usr/include/c++/4.7/string:50,
from /usr/include/c++/4.7/bits/locale_classes.h:42,
from /usr/include/c++/4.7/bits/ios_base.h:43,
from /usr/include/c++/4.7/ios:43,
from /usr/include/c++/4.7/ostream:40,
from /usr/include/c++/4.7/iostream:40,
from template2.cpp:3:
/usr/include/c++/4.7/backward/binders.h: In instantiation of ‘std::binder2nd<_Operation> std::bind2nd(const _Operation&, const _Tp&) [with _Operation = std::plus<int>; _Tp = my_data<int>]’:
template2.cpp:20:5: required from ‘void my_data<T>::add(U) [with U = my_data<int>; T = int]’
template2.cpp:45:10: required from here
/usr/include/c++/4.7/backward/binders.h:170:57: error: invalid cast from type ‘const my_data<int>’ to type ‘_Arg2_type {aka int}’


The code of adding two my_data objects together does not seem to be used. Of course <typename U> can be objects of type X as well as my_data<X> but how do I let the compiler know when to use the second version of add()?


My current version of the program uses



void add (const bisArray<U> addition, const std::true_type&)


for adding an element and



void add (const bisArray<U> addition, const std::false_type&)


for adding a my_data object (the calls are a.add(2, std::is_arithmetic<int>::type() ); for adding an element and a.add(a, std::is_arithmetic<my_data<int>>::type() ); for adding a my_data object).


It is not really a solution though because there is nothing to prevent the occurrence of the calls a.add( a , std::is_arithmetic<int>::type() ); and a.add( 2 , std::is_arithmetic<my_data<int>>::type() ); which lead to a segmentation fault.


Is there a mechanism to resolve this more elegantly?


Aucun commentaire:

Enregistrer un commentaire