добрый день, коллеги! исходный код чуть сложнее, но попробую задачу описать на урощенном примере. с++0х позволяет вычислять константные выражения на стадии компиляции, напрмер:
constexpr size_t max(size_t x, size_t y) {return (x > y) ? x : y;}
void main() {
enum {one, two};
enum {max_of = max(one, two)};
std::cout << "max_of=" << unsigned(max_of) << std::endl;
}
результатом будет: max_of=1
Хотелось бы получить что-то подобное в следующем случае. Есть класс Foo с перегруженными методами и функция main, которая не компилится:
struct Foo{
template <typename T> void exec(T);
void exec(unsigned val){
std::cout << "exec(unsigned)=" << val << std::endl;
}
};
void main() {
Foo foo;
size_t uvar = 5;
foo.exec(uvar);
foo.exec(5); // <<<<< error: undefined reference to `void Foo::exec<int>(int)'
}
Решается, конечно, легко, добавлением суффикса "u" к литералу: foo.exec(5u);
Можно разрешить проблему через перегрузку метода exec, в качестве параметра которого определить rvalue ссылку:
struct Foo{
void exec(unsigned val){
std::cout << "exec(unsigned)=" << val << std::endl;
}
template <typename T>
void exec(T&& lit) {
std::cout << "exec(T&&, N)" << std::endl;
if (lit < 0)
throw std::runtime_error("must be unsigned");
typedef typename std::make_unsigned<T>::type UT;
exec(static_cast<UT>(lit));
// enum {val = lit};
}
};
Код компилится, но проблему перенесли в runtime. Если в main функции написать ошибочно foo.exec(-5); то об ошибке узнаем только в момент работы программы. Раскомментировать перечисление enum {val = lit}; компилятор не позволит: "error: 'lit' is not a constant expression", не поможет и объявление метода таким образом: void exec(T const&& lit). Хотя, как мы видели выше с примером max_of компилятор справляется. В последнем примере компилятор "тоже может увидеть", что в метод передаётся константный литерал, который и вычислять не надо, но как ему об этом корректно сказать?
Существует ли какая-либо декларация (constexpr, квалификатор и т.п.), что позволило бы без добавления суффикса "u" определиться положительный литерал, переданный в метод exec(..), или вычислить в нём "enum {val = lit}" (тогда решилось бы через шаблон)? Понимаю, что здесь концептуальные ограничения, но может еть какая-нибудь хитрость или банальность, которую я со своей кочки не вижу?
(работаю с gcc 4.6.3, -std=c++0x, более свежую версию компилятора применить не могу из-за производственных ограничений)