Я пытаюсь добиться проверки типа параметров класса шаблона, запретив неявные преобразования типов, такие как string-> bool, тем самым выдавая ошибку компиляции.
Конкретный сценарий прост:
#include <iostream>
#include <string>
using namespace std;
template <class T>
class myPair {
T a, b;
public:
myPair(T first, T second ) {
a = first;
b = second;
}
void test();
};
typedef myPair<bool> boolParm;
template<class T>
void myPair<T>::test() {
if(a == true) {
cout << "a is true" << endl;
} else {
cout << "a is false" << endl;
}
if(b == true) {
cout << "b is true" << endl;
} else {
cout << "b is false" << endl;
}
}
int main() {
boolParm myObj(false, "false");
myObj.test();
return 0;
}
Вывод описанного выше сценария нежелателен, поскольку пользователь может непреднамеренно передать 2 различных типа: bool и string и получить первый как false (правильный, так как переданный как bool), но второй будет true (неверный, поскольку неявное преобразование типа из строки кипеть).
Я хочу ограничить пользовательский код в main (), чтобы он выдавал ошибки компиляции и не позволял передавать параметры string / int в конструктор. Следует только разрешить bool.
Я попытался с помощью перегруженного конструктора myPair (сначала bool, затем string), но он не совпадал, так как я предполагаю, что неявное преобразование типа из string-> bool происходит до вызова конструктора.
Есть ли какое-либо решение с использованием шаблонных специализаций в этом сценарии?
Любая помощь высоко ценится
Спасибо
Один из обходных путей — добавить шаблонную фабричную функцию для создания myPair.
template <typename T>
myPair<T> makeParam(T a, T b) {
return myPair<T>(a, b);
}
Это не удастся скомпилировать с неоднозначным параметром шаблона T, если типы не совпадают. Вы можете расширить это с помощью специализаций шаблонов, явно запрещающих определенные типы для T. Ваша основная функция будет выглядеть примерно так:
int main() {
boolParm myObj = makeParam(false, "false");
myObj.test();
return 0;
}
В качестве альтернативы измените конструктор:
template <typename U, typename V>
myPair(U a, V b);
И специализируюсь по мере необходимости
Пример такой специализации:
template <class T>
class myPair {
T a, b;
public:
template <typename U, typename V> // generic version
myPair(U first, V second)
{
// intentionally fail to compile
static_assert(false, "don't support generic types");
}
template <> // template specialization
myPair(T first, T second)
{
// explicitly require exactly type T
a = first;
b = second;
}
};
Это действительно странное поведение на первый взгляд; но, насколько я могу сказать, вы не можете запретить это — не для примитивных типов, таких как bool
, тем не мение.
Неявное преобразование параметров происходит до того, как вы о нем узнаете, и кажется, что существует неявное преобразование примитивного типа из char const *
в bool
,
Смотрите также, например, этот другой вопрос: Почему строка в кавычках соответствует сигнатуре метода bool перед std :: string?