2013-06-21 5 views
1

Я знаю, что стандарт ISO C делает большую сделку относительно разделения поведения перевода и поведения выполнения, отчасти для обеспечения того, чтобы кросс-компиляторы не могли нести среду выполнения каждой цели.C++ 11 определенные пользователем литералы, конфликты с компиляцией/выполнением дихотомии

Под этим я имею в виду, что у компилятора есть ограниченная информация, доступная ему по сравнению с запущенной программой. Это ограничивает то, что вы можете сделать в исходном коде, например, не инициализацией переменной на основе значения, возвращаемого из функции, как это:

int twice (int val) { return val * 2; } 
int xyzzy = twice (7); 
int main() { printf ("%d\n", xyzzy); return 0; } 

Что мне любопытно, как это определяется пользователем литералов в C++ 11 вписываются в эту схему. Поскольку буквальная оценка опирается на функции, что остановить эту функцию, делая такие вещи, как:

  • возвращает случайное значение (даже если на основе ввода, такие как 42_roughly дает вам значение от 40 до 44 лет)?
  • с побочными эффектами, такими как изменение глобальных переменных?

ли тот факт, что функция должны называться означает, что эти не действительно литералы в том смысле, что вычисляется во время компиляции?

Если это так, то в чем преимущество этих литералов над любым вызовом функции. Другими словами, почему:

int xyzzy = 1101_1110_b; 

предпочтительнее:

int xyzzy = makeBin ("1101_1110"); 

?

ответ

6

Секрет в том, объявляете ли вы определяемые пользователем функции литерала как constexpr или нет.

Сравните это (нормальную функцию выполнения времени):

#include <iostream> 
int operator "" _twice(unsigned long long num) { return num*2; } 
int xyzzy = 7_twice; 
int main() { std::cout << xyzzy << "\n"; return 0; } 

С этим (во время компиляции постоянная, то static_assert работы):

#include <iostream> 
constexpr int operator "" _twice(unsigned long long num) { return num*2; } 
int xyzzy = 7_twice; 
int main() { 
    static_assert(7_twice == 14, "not compile time constant"); 
    std::cout << xyzzy << "\n"; 
    return 0; 
} 

Очевидно, что декларирование функции constexpr ограничивает все заявления внутри также должно быть constexpr, или константы времени компиляции; не допускается случайное число махинаций.

+0

Таким образом, предположим, что если вы объявите его 'constexpr', его можно полностью оценить во время компиляции (хотя я понимаю, что это может вызвать проблемы при кросс-компиляции в среду с разными правилами - перекрестный компилятор должен будет нести много выполнения или отложить расчет до времени выполнения). Без 'constexpr', возможно, придется отложить вычисление в любом случае. Я убеждаюсь, что использую 'constexpr' :-) – paxdiablo

+0

@paxdiablo Я не знаю, что кросс-компиляция повлияет на' constexpr'; однако из [этого ответа] (http://stackoverflow.com/a/14248310/2038264) представляется, что для гарантирования времени компиляции 'constexpr' его аргументы должны быть также' constexpr'. – congusbongus

+4

@paxdiablo: выражения 'constexpr' строго ограничены до такой степени, что кросс-компиляторы должны иметь возможность их оценивать. Кросс-компиляторы всегда могли оценивать довольно сложные выражения: 'int foo [(7/3 == 3)? 4: (5> 2? Bar <6> :: baz: 2]' должны оцениваться во время компиляции. То, что «constexpr» в первую очередь добавляет, - это способность к _name_ определенным выражениям. – MSalters

 Смежные вопросы

  • Нет связанных вопросов^_^