Может ли ключевое слово & quot; явное & quot; быть удаленным из конструктора в одном конкретном экземпляре шаблона?

Я пытаюсь создать шаблонный класс для обеспечения корректности размеров (длина, деленная на время, дает скорость и т. Д.).

Короткая история: «Безразмерный» является одним из возможных воплощений. Было бы удобно, если бы я мог позволить все экземпляры могут быть явно созданы из двойников и, кроме того, позволяют «безразмерному» экземпляру (и только безразмерному экземпляру) быть неявно построенным из двойников.

Длинная история: Мой шаблон класса выложен как

template<int iLength, int iTime, int iMass>
class qty {
double data;

//Operators overloaded to enforce dimensional correctness
//  e.g. qty<a,b,c> can only be added to qty<a,b,c>
//       qty<a,b,c> * qty<a2,b2,c2> returns qty<a+a2,b+b2,c+c2>

};

Следуя этому стилю, qty<0,0,0> является безразмерной величиной, поэтому можно добавить или вычесть qty<0,0,0> и двойной. Я в настоящее время принудил это декларирование

    qty operator+ (const double& rhs) const;

…но только определяющий это для qty<0,0,0>, Это выполнимо … но я думаю, что мог бы сделать лучше. Если бы я позволил неявное преобразование из двойного в qty<0,0,0>затем сложение двойного и qty<0,0,0> не требует специальной обработки. Пользовательские ошибки также могут давать более многообещающие сообщения об ошибках — попытка добавить удвоение к скорости будет означать, что преобразование невозможно (исходя из основной идеи несовместимости измерений), а не будет жаловаться, что функция не определена ( что может заставить пользователей заподозрить ошибку в классе шаблона).

Проблема в том, что я не могу разрешить неявную конструкцию для любой другой комбинации параметров шаблона. Если бы я это сделал, то добавление любого кол-во и двойного всегда будет успешным; Я хочу заставить пользователя задуматься о корректности размеров и явно преобразовать двойные константы в соответствующее измерение перед добавлением (если это предполагаемая операция). Я, однако, хочу разрешить явный конструкция из двойников — без нее простая декларация

qty<1,-1,0> a(1.5); //speed with value 1.5

понадобится неуклюжая функция преобразования

qty<1,-1,0> a = makeQty<1,-1,0>( 1.5 ); //my eyes hurt

Это означает, что я действительно хочу

template<int iLength, int iTime, int iMass>
class qty {
double data;
explicit qty(const double& rhs) : data(rhs) {} //general version prohibits
//implicit conversion

//...
};

template<>
qty<0,0,0>::qty(const double&rhs) : data(rhs) {} //Explicit instantiation
//for dimensionless case
// ... with black magic to reallow implicit conversion
// for this instantiation only ???

Как видите, я не уверен, возможно ли удалить explicit спецификация только для одного экземпляра, и — если это возможно — я не уверен, каков синтаксис.

1

Решение

Мы создаем тип, который T или тип, который вы не можете создать в зависимости от bool:

template<bool b, typename T>
struct block_unless {
struct type { type() = delete; operator T(); }; // operator T is standard-paranoia
};
template<typename T>
struct block_unless<true, T> {
using type = T;
};
template<bool b, typename T>
using block_unless_t = typename block_unless<b,T>::type;
template<bool b, typename T>
using block_if_t = block_unless_t<!b, T>;

Затем мы защищаем методы, которые мы хотим заблокировать / активировать, встроенными в остальную часть кода:

template<int a, int b, int c>
struct qty {
enum { scalar = (a==0)&&(b==0)&&(c==0) };
explict qty( block_if_t< scalar, double > d );
qty( block_unless_t< scalar, double > d );
};

как насчет этого?

В C ++ 1y предложения require, вероятно, будут работать лучше.

(Стандартная паранойя возникает из-за недосказанности в стандарте, когда шаблонный метод должен иметь хотя бы одну действительную реализацию: пока он недоступен, operator T означает, что ваш код работает с d будет работать в 99% случаев, когда код ожидает double.)

1

Другие решения

Вы не можете изменить это напрямую, но следующее будет работать с C ++ 11:

template<int iLength, int iTime, int iMass>
class qty_impl {
double data;
public:
explicit qty_impl(const double& rhs) : data(rhs) {} //general version prohibits
//implicit conversion

//...
};

// general case: simply forward to _impl
template<int iLength, int iTime, int iMass>
class qty : public qty_impl<iLength,iTime,iMass> {
// inherit ctors, including "explicit"using qty_impl<iLength,iTime,iMass>::qty_impl;
};

// special case
template<>
class qty<0,0,0> : public qty_impl<0,0,0> {
using qty_impl<0,0,0>::qty_impl;
public:
// provide non-explicit ctor to override the inherited base ctors
qty(const double& rhs) : qty_impl<0,0,0>(rhs) {}
};

Это позволяет вам поддерживать общую реализацию практически для всего и просто пересылать неявный ctor в явный.

0

По вопросам рекламы [email protected]