Все никак не уймусь с шаблонами. Один раз у меня возникла некая задача:
Есть какой-то класс, в конструктор которого передается целое число. Требование для пользователя класса - целое должно быть больше нуля и нечетным. Оставался вопрос. Как заставить пользователя передать правильные данные? Для начала нужен правильный комментарий о том что и как, а далее есть варианты:
1. Проверить в конструкторе переданый аргумент, и если он не правильный, то:
– бросить исключение об ошибке(если можно бросать исключения);
– вернуть out-parameter как результат работы конструктора.
2. Если аргумент не правильный, то «привести» его к правильному, правда не понятно в какую сторону.
В принципе я бы выбрал первый вариант и не заморачивался бы. Но вот я вспомнил про проверку во время компиляции которую описывал Александреску. В итоге можно сделать так, что если пользователь класса передаст константу известную во время компиляции – то можно проверить ее при компиляции и если целое не верное – то выдать ошибку. Вот примитивный вариант самой проверки во время компиляции:
// cmnStaticAssert.h
#ifndef __CMN_STATIC_ASSERT_H__
#define __CMN_STATIC_ASSERT_H__
namespace utils
{
template < bool > struct static_assert;
template < > struct static_assert < true > { };
} // utils
#define STATIC_ASSERT(val, msg) \
{ \
utils::static_assert <((val) != 0)> ERROR_##msg; \
(void)ERROR_##msg; \
}
#endif // __CMN_STATIC_ASSERT_H__
Этот код я взял(немного переделав) из библиотеки Loki. Также есть в boost более продвинутая реализация, но сейчас для идеи хватит и этого.
Теперь его применение:
#include "cmnStaticAssert.h"
#include < crtdbg.h >
template < int TSize = 1 >
class CTest
{
int size_;
public:
CTest() : size_(TSize)
{
STATIC_ASSERT(TSize % 2 && TSize > 0, invalid_argument_format);
}
CTest(int size) : size_(size)
{
if (!(size % 2) || size < 1) throw 0;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
// Во время компиляции для константы
{
CTest<11> compile_time_test;
}
// Во время выполнения для переменной
{
int n = 11;
try
{
CTest<> run_time_test(n);
}
catch(...) { _ASSERTE(false); }
}
return 0;
}
Если в первом случае будет: CTest<12> compile_time_test;
то будет ошибка компиляции:
error C2079: 'ERROR_invalid_argument_format' uses undefined struct 'utils::static_assert<__formal>' e:\test\test\test.cpp 13
Во втором случае, если int n = 12;
будет сгенерированно исключение и в обработчике сработает assert.Тоже самое касается параметров меньше единицы.