C++ Принудительное неявное преобразование при передаче в качестве аргумента.
У меня проблема с неявными преобразованиями в C++.
Я пытаюсь создать шаблон Expression для векторной арифметики (я знаю, что такие же библиотеки уже существуют. Я просто изучаю C++, поэтому я хотел попробовать что-то с шаблонами).
Я хотел бы создать класс Vector, способный вычислять так:
simd::test::Vector<char, 5> a;
simd::test::Vector<short, 5> b;
auto ret = a + b + a + b;
, где на выходе будет Vector of shorts, потому что short - это больший тип, чем char.
Прямо сейчас у меня есть класс, который может добавлять векторы одинаковых типов данных. Для разных типов я должен назвать явное преобразование:
//simd::test::Vector<short, 5>(a)
auto ret = simd::test::Vector<short, 5>(a) + b + simd::test::Vector<short, 5>(a) + b;
Возможно ли неявное преобразование Vector перед передачей в функцию "operator+()"? Вот мой код Vector:
#pragma once
#include <type_traits>
namespace simd {
namespace test {
template<typename R, std::size_t Dim,
typename std::enable_if<std::is_arithmetic<R>::value>::type* = nullptr
>
class Vector_expression {
public:
static constexpr std::size_t size = Dim;
virtual const R operator[] (std::size_t index) const = 0;
virtual ~Vector_expression() = default;
};
template<typename T, std::size_t Dim>
class Vector final : public Vector_expression<T, Dim> {
private:
T data[Dim];
public:
Vector() = default;
template<typename R>
Vector(const Vector_expression<R, Dim> &obj) {
for(std::size_t index = 0; index < Dim; ++index) {
data[index] = obj[index];
}
}
template<typename R>
Vector(Vector_expression<R, Dim> &&obj) {
for(std::size_t index = 0; index < Dim; ++index) {
data[index] = obj[index];
}
}
template<typename R>
Vector<T, Dim> & operator=(const Vector_expression<R, Dim> &obj) {
for(std::size_t index = 0; index < Dim; ++index) {
data[index] = obj[index];
}
return (*this);
}
template<typename R>
Vector<T, Dim> & operator=(Vector_expression<R, Dim> && obj) {
for(std::size_t index = 0; index < Dim; ++index) {
data[index] = obj[index];
}
return (*this);
}
virtual const T operator[] (std::size_t index) const override {
return data[index];
}
T & operator[] (std::size_t index) {
return data[index];
}
virtual ~Vector() = default;
};
template<typename E1, typename E2, typename R, std::size_t Dim>
class Vector_sum final : public Vector_expression<R, Dim> {
private:
const E1 & _lhs;
const E2 & _rhs;
public:
Vector_sum() = delete;
Vector_sum(const E1 & lhs, const E2 & rhs) :
_lhs(lhs),
_rhs(rhs)
{}
virtual const R operator[] (std::size_t index) const override {
return _lhs[index] + _rhs[index];
}
virtual ~Vector_sum() = default;
};
template<typename R, std::size_t Dim>
Vector_sum<Vector_expression<R, Dim>, Vector_expression<R, Dim>, R, Dim> operator+ (const Vector_expression<R, Dim> & lhs, const Vector_expression<R, Dim> & rhs) {
return {lhs, rhs};
}
}
}
2 ответа
Просто определите operator+
это позволяет разные типы аргументов. Один улов определяет тип элемента результирующей суммы. Вероятно, лучший вариант - использовать любой результат добавления двух элементов. Один из способов написать этот тип:
decltype(std::declval<const R1>() + std::declval<const R2>())
Или, если вы знаете, что типы являются встроенными арифметическими типами, это было бы так же, как
std::common_type_t<R1, R2>
Или используя конечный тип возврата, мы можем воспользоваться параметрами функции, чтобы сократить std::declval
выражения:
template<typename R1, typename R2, std::size_t Dim>
auto operator+ (const Vector_expression<R1, Dim> & lhs,
const Vector_expression<R2, Dim> & rhs)
-> Vector_sum<Vector_expression<R1, Dim>, Vector_expression<R2, Dim>,
decltype(lhs[0] + rhs[0]), Dim>
{
return {lhs, rhs};
}
Это можно сделать с помощью шаблонов и std::common_type
, что-то вроде этого:
template<typename T1, typename T2, size_t S>
simd::test::Vector<typename std::common_type<T1, T2>::type, S>
operator+(simd::test::Vector<T1, S> const& v1,
simd::test::Vector<T2, S> const& v2)
{
// TODO: Implementation...
}