#c #templates #visual-c #c 17 #c 14
Вопрос:
У меня есть векторный класс, основанный на шаблонах. У меня есть шаблон преобразования единиц измерения, основанный на анализе измерений Скотта Мейерса в C . Я не собираюсь перечислять это, поскольку это сложно, если только проблема не может быть решена без этих деталей. Я использую оператор приведения, когда мне нужно передать данные внешним функциям.
template<typename T>
struct XYZVector
{
operator Point3D() { return Point3D(x, y, z); }
}
Если я использую T как double, он работает нормально. Но когда я это делаю, мне нужна специализация.
Point3D vecOut = XYZVector<Unit::usFoot>(x,y,z);
Произойдет сбой, потому что при преобразовании объекта Unit вам нужно использовать метод as() .
operator Point3D() { return Point3D( x.as<T>(), y.as<T>(), z.as<T>() ); }
Итак, мне нужно как-то сказать, что если T является единицей, используйте эту строку, в противном случае используйте следующую строку.
template<typename T>
struct XYZVector
{
//if typename T is a Unit type use this
operator Point3D() { return Point3D( x.as<T>(), y.as<T>(), z.as<T>() ) }
//otherwise use this
operator Point3D() { return Point3D(x, y, z); }
}
Возможно ли это?
Ответ №1:
if constexpr
на помощь.
operator Point3D() {
if constexpr (std::is_same_v<std::remove_cvref_t<T>,Unit>){
return Point3D(x.as<T>(),y.as<T>(),z.as<T>());
}else{
return Point3D(x,y,z);
}
}
Комментарии:
1. Общая идея хорошая, но код не совсем правильный.
Unit
это не тип. В идеале это должно быть обработано с помощью концепции, ноis_unit_type<T>::value
тип признака был бы более обратно совместим.2. @Frank, приведенный Staz пример не сработал для меня, и я думаю, что вы намекали на это и предлагали лучший способ. Но я не уверен, как это реализовать. Не могли бы вы привести пример? Спасибо
3. @MarkTwombley я вроде как использовал
Unit
в качестве заполнителя для типа. Вы можете заменить его соответствующим образом. Такжеstd::remove_cvref
являетсяC 20
признаком типа. Вы можете использоватьstd::remove_cv_t<std::remove_reference_t<T>>
вместо этого, если ваш стандарт cpp ниже 20.4. Спасибо @Staz за это обновление. У меня это работает.
Ответ №2:
Я бы использовал перегрузки в качестве точки настройки:
// overload for built-in type (no ADL)
double to_double(double d) { return d;}
template <typename T>
struct XYZVector
{
// ...
operator Point3D() const {
return Point3D(to_double(x),
to_double(y),
to_double(z));
}
};
// The ones which can be found by ADL can be placed after
namespace Unit {
double to_double(usFoot u) { return u.as<double>(); }
}