могу ли я предотвратить создание функции шаблонного класса, если аргументы шаблона не соответствуют критериям (определенное значение или тип)? Можно ли этого добиться, используя код С++ и не используя директивы препроцессора?
Такого рода функции не должны быть доступны ни в заголовке, ни в теле. Этот случай может показаться немного искусственным, но я пока не нашел решения.
Пример класса (упрощенный - без конструктора и т.д.):
МойКласс.h
template<int Dimension, typename TPixelType = float>
class MyClass
{
void DoSomething();
void DoAnotherThing(); // this function should only be available if Dimension > 2
}
MyClass.cxx
template< int Dimension, typename TPixelType> void MyClass::DoSomething()
{...}
// pseudocode: if Dimension <= 2 do not compile next function
template< int Dimension, typename TPixelType> void MyClass::DoAnotherThing()
{
MethodNotToBeCompiled(); // The function I don't want to be executed
}
TestMyClass.cxx
int main()
{
auto myclass0 = MyClass<2>();
myclass0.DoSomething(); // OK
myclass0.DoAnotherThing(); // (wanted) error - function not available
auto myclass1 = MyClass<3>();
myclass1.DoSomething(); // OK
myclass1.DoAnotherThing(); // OK
}
Возможно ли это в C++XX? Или есть другой подход, чем директивы препроцессора?
из любопытства: как бы вы использовали препроцессор? Я понятия не имею, как это можно сделать с помощью препроцессора.
Вы можете специализировать шаблоны, так что это концептуально тривиально. Другое дело, как написать "хороший" код для больших классов шаблонов со специализациями (может помочь наследование). Но, возможно, в вашем случае достаточно и SFINAE.
static_assert(2 < Dimension)




template <int Dimension, typename TPixelType> void MyClass::DoSomething() {/*...*/}
// if Dimension <= 2 do not compile next function
template <int Dimension, typename TPixelType>
void MyClass::DoAnotherThing()
{
static_assert(Dimension > 2, "function not available!" );
// ...
}
Как мне обрабатывать код после static_assert()? Кажется, что static_assert влияет на весь процесс компиляции. Я просто хочу, чтобы единственная функция не компилировалась.
что ты имеешь в виду? когда вы используете эту функцию с недопустимым параметром (<=2), компилятор не позволяет вам это сделать и выдает ошибку function not available!. Код после static_assert() должен быть как обычный код, разницы нет. В примере после static_assert(...); можно поставить: int i = Dimension * 3;
Предотвращает ли утверждение компиляцию этого метода или только его выполнение? Я пытаюсь выяснить, в какой момент static_assert раскрывает свою функциональность.
@KabCode static_assert выдает ошибку времени компиляции, поэтому компиляция невозможна.
В C++2a вы можете использовать requires для "отбрасывания" метода:
template<int Dimension, typename TPixelType = float>
class MyClass
{
void DoSomething();
void DoAnotherThing() requires (Dimension > 2);
};
Как далеко продвинулась реализация C++2a? Может ли он уже использоваться (с визуальным компилятором)?
Вы можете посмотреть на docs.microsoft.com/en-us/cpp/overview/…. Так что в настоящее время еще не поддерживается в Visual (gcc поддерживает requires).
Это был бы мой предпочтительный ответ, если бы я мог использовать requires.
@Jarod42 слишком опередил свое время :-) тем не менее, классное решение, счастлив, что попробовал это!
Общее предложение: если у вас есть класс шаблона, реализуйте все в заголовке и избегайте файлов cpp. Все стало намного проще.
can I prevent the generation of a function of a templated class if the template arguments does not meet a criteria (certain value or type)? Can this be achieved by using c++ code and no preprocessor directives?
Да и да: ищите SFINAE.
В вашем случае (С++ 11 и новее)
template <int Dimension, typename TPixelType = float>
class MyClass
{
public:
void DoSomething ()
{ }
template <int D = Dimension,
typename std::enable_if<(D > 2), bool>::type = true>
void DoAnotherThing()
{ }
};
Теперь метод DoAnotherThing() реализуется только тогда, когда D > 2 где D по умолчанию равно Dimension.
Не идеальное решение, потому что его можно «угнать», объясняя значение D
auto myclass0 = MyClass<2>();
myclass0.DoAnotherThing<5>(); // compile because D is 5
но вы можете предотвратить эту проблему, добавив тест, что D равно Dimension
template <int D = Dimension, // ..VVVVVVVVVVVVVVVV
typename std::enable_if<(D == Dimension)
&& (D > 2), bool>::type = true>
void DoAnotherThing()
{ }
так
auto myclass0 = MyClass<2>();
myclass0.DoAnotherThing<5>(); // doesn't compile anymore because 5 != 2
Это можно комбинировать с if constexpr(){}, чтобы предотвратить вызов функции, вызывающий ошибки времени компиляции.
не вопрос, но актуально: stackoverflow.com/questions/495021/…