compiled time unsigned type deduction
От: __smit Россия  
Дата: 23.08.13 10:20
Оценка:
добрый день, коллеги! исходный код чуть сложнее, но попробую задачу описать на урощенном примере. с++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, более свежую версию компилятора применить не могу из-за производственных ограничений)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.