#cpp
Можно ли определить тип переданных параметров variadic templates, на этапе компиляции? Хочу использовать static_assert для проверки допустимости передачи параметра в шаблон. Допустим запретить передачу в шаблон типа float int main() { MyClassobj; // так можно MyClass obj; // так тоже MyClass obj; // а вот так нельзя return 0; }
Ответы
Ответ 1
Как уже ответил @AnT, в C++17 появились fold expressions. Если использование C++17 недоступно, то можно сделать следующим образом: templatestruct any_of; template struct any_of : any_of {}; template struct any_of : std::true_type {}; template struct any_of : std::false_type {}; //использование template struct MyClass { static_assert(!any_of ::value, "float not supported"); }; //... MyClass d1;//ok MyClass d2;//assertion Для понимания работы этого кода предлагаю разобраться сначала с возможной реализацией is_same для двух типов: //Общая версия шаблона наследуется от std::false_type, //что дает сразу готовый член value и операцию преобразования к bool. //false_type::value имеет значение false template struct my_is_same: std::false_type {}; //Весь "фокус" в данной специализации. //Данная специализация будет выбрана, если типы переданные в шаблон одинаковые (T и T). //И эта специализация наследуется от std::true_type, ///и член value равен true template struct my_is_same : std::true_type {}; //... static_assert(my_is_same ::value, "failure"); //ок - my_is_same здесь наследник std::true_type static_assert(my_is_same ::value, "failure"); //ошибка - my_is_same здесь наследник std::false_type Думаю, прием с наследованием от false_type и true_type понятен. В начальном коде используется еще один прием - наследование в шаблоне класса от самого себя с другим набором аргументов шаблона. Разберем и его на примере первоначального кода. //Общая версия шаблона не реализуется и не используется //Вместо нее будут использоваться специализации template struct any_of; //Данная специализация выбирается если параметров более одного. //any_of в данном случае наследуется от any_of, при этом отсекается параметр HeadType, //т.е. он не передается в качестве аргумента шаблону базового класса. //Таким образом с каждой "ступенью" наследования отсекается один тип из списка аргументов. //при этом отсекается второй тип (HeadType), т.к. первый (CheckType) - //это тот тип, который необходимо проверить. template struct any_of : any_of {}; //Наследование и "отсечение" будет происходить до тех пор, //пока не упремся в одну из следующих специализаций: //Эта специализация будет выбрана, если первый и второй параметры шаблона одинаковы. //Здесь уже используется наследование от std::true_type, //что прерывает цепочку наследования от any_of, //таким образом any_of становится наследником std::true_type, //если хоть один аргументов, переданных изначально в any_of, совпадает с первым аргументом. template struct any_of : std::true_type {}; //если же мы дошли до такого момента, когда остался только проверяемый тип, //значит в списке аргументов any_of не было типов, совпадающих с первым, //поэтому прерываем наследование от any_of наследованием от std::false_type. template struct any_of : std::false_type {}; //Таким образом, если в пакете Args... в any_of есть тип Type, //то any_of станет наследником std::true_type, //в ином случае any_of станет наследником false_type static_assert(any_of ::value, "float not supported");//ok - any_of наследник std::true_type static_assert(any_of ::value, "float not supported");//ошибка - any_of наследник std::false_type Ответ 2
Весь template type deduction работает именно на этапе компиляции. То есть, когда вы определяете объект шаблонного класса, компилятор скомпилирует используемый класс именно с подставленным типом в шаблонный параметр. Если вы по каким-то причинам хотите запретить пользователю использовать в качестве параметра какой-то определенный тип, то вы должны запретить конструктор для данного шаблона с таким параметром (типом). Пример : templateclass Foo { public: T a; }; template class Foo { public: Foo() = delete; }; Если вы попытаетесь создать объект Foo , то компилятор выдаст ошибку. Отвечая на вторую часть вопроса про static_assert. В данном случае можно попробовать определить тип именно так static_assert(std::is_same ::value, "retval must be bool"); Принцип использования должен быть понятен Ответ 3
Для этого фактически и предназначены fold expressions в C++17 #includetemplate class MyClass { static_assert(!(... || std::is_same_v )); };
Комментариев нет:
Отправить комментарий