这对我来说就像一个基本问题,所以请提前为重复的帖子道歉。不知道术语是什么。
我有一个班级,比如my_data
,用于存储数字。它具有基本的构造函数等,并且支持基本操作(例如添加元素,例如元素)将是很方便的。增加数据中的值。
这是描述课程的最基本方式:
#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(),
std::plus<T>() );
}
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);
}
当我想将一个对象的值添加到另一个对象的值时,问题就开始了(在这里滥用这个事实,它们的大小相同,省略了检查):
$ 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}’
似乎没有使用将两个my_data
个对象添加到一起的代码。当然<typename U>
可以是X
类型的对象以及my_data<X>
但是如何让编译器知道何时使用第二版add()
?
我当前的程序版本使用
void add (const bisArray<U> addition, const std::true_type&)
用于添加元素和
void add (const bisArray<U> addition, const std::false_type&)
用于添加my_data
对象(调用a.add(2, std::is_arithmetic<int>::type() );
用于添加元素,a.add(a, std::is_arithmetic<my_data<int>>::type() );
用于添加my_data
对象。
这不是一个真正的解决方案,因为没有什么可以阻止调用a.add( a , std::is_arithmetic<int>::type() );
和a.add( 2 , std::is_arithmetic<my_data<int>>::type() );
的出现导致分段错误。
有没有一种机制可以更优雅地解决这个问题?
答案 0 :(得分:1)
您的代码存在许多问题。 {/ 3}}已在评论中指出了代码未编译的最直接原因。
我将从“声明顺序”开始,这不是严重性的顺序:
#include
std::size_t
的正确标头不是stdlib.h
,而是cstddef
。 (一般情况下,不要#include
*.h
而是c*
版本。)explicit
的构造函数。当整数突然转换为my_data
时,它可以避免意外情况。std::vector<T>
的构造函数不必要地复制其参数。至少,你应std::move
进入目的地。您可能还需要考虑为const std::vector<T>&
(执行副本)和std::vector<T>&&
(执行此操作)提供重载。{ … }
)。+=
和<<
,而不是提供命名成员函数。std::transform
无法判断第二和第三范围有多长。std::transform
调用中,应提供二进制函数。由于您已模板化该功能,因此std::plus<T>
和std::plus<U>
均不适用。使用添加T
和U
的lambda。如果例如T = std::string
和U = char *
。让我们把所有这些放在一起:
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <vector>
template<typename T>
class my_data
{
public:
my_data()
{
}
explicit my_data (const std::size_t size)
{
data.resize(size);
}
explicit my_data(const std::vector<T>& init) : data {init}
{
}
explicit my_data(std::vector<T>&& init) : data {std::move(init)}
{
}
template<typename U>
void
operator+=(const U& a)
{
std::transform(data.begin(),
data.end(),
data.begin(),
[&a](const T& b){ return a + b; });
}
template<typename U>
void
operator+=(const my_data<U>& other)
{
if (other.data.size() != this->data.size())
throw std::invalid_argument {"incompatible sizes"};
std::transform(data.begin(),
data.end(),
other.data.begin(),
data.begin(),
[](const T& a, const U& b){ return a + b; });
}
friend
std::ostream&
operator<<(std::ostream& os, const my_data& md)
{
std::ostream_iterator<T> outit {os, ", "};
std::copy(md.data.begin(), md.data.end(), outit);
return os;
}
protected:
std::vector<T> data {};
};
int main() {
std::vector<int> inttest {1, 2, 3};
my_data<int> a {inttest};
std::cout << a << std::endl;
a += 2;
std::cout << a << std::endl;
a += a;
std::cout << a << std::endl;
}
输出:
1, 2, 3,
3, 4, 5,
6, 8, 10,
您可能希望解决的另一件事是输出中多余的尾随逗号。