Почему нельзя использовать параметры constexpr?

Было бы полезно иметь параметры constexpr, чтобы различать значения, известные компилятору, и таким образом иметь возможность обнаруживать ошибки во время компиляции. Примеры:

int do_something(constexpr int x)
{
  static_assert(x > 0, "x must be > 0");
  return x + 5;
}

int do_something(int x)
{
  if(x > 0) { cout << "x must be > 0" << endl; exit(-1); }
  return x + 5;
}

int var;

do_something(9); //instance 'do_something(constexpr int x)' and check arg validity at compile-time

do_something(0); //produces compiler-error

do_something(var); //instance 'do_something(int x)'

Это недействительный код на данный момент. Может кто-нибудь объяснить мне, почему это невозможно реализовать?

РЕДАКТИРОВАТЬ:

Используя шаблоны, пользователи должны гарантировать, что литералы всегда передаются как аргументы шаблона, а не как функциональные, что очень неудобно:

template<int x>
int do_something()
{
  static_assert(x > 0, "x must be > 0");
  return x + 5;
}

int do_something(int x)
{
  if(x > 0) { cout << "x must be > 0" << endl; exit(-1); }
  return x + 5;
}

int var;

do_something(9); //instance 'do_something(int x)' and doesn't checks validity at compile-time

do_something(0); //same as above, if check was performed - compiler error should occur

do_something<9>(); //instance template 'do_something<int>()'

do_something<0>(); //produces compiler error

do_something(var); //instance 'do_something(int x)'

person AnArrayOfFunctions    schedule 21.12.2014    source источник
comment
Разве вы уже не можете сделать это с помощью шаблона? Точнее, с параметрами шаблона, не являющимися типами?   -  person Borgleader    schedule 21.12.2014
comment
Затем пользователь моей функции должен предоставить другой синтаксис для ее вызова в зависимости от того, известен ли параметр во время компиляции.   -  person AnArrayOfFunctions    schedule 21.12.2014
comment
Предположительно, assert () может быть оптимизирован в случае передачи значения constexpr.   -  person Cory Nelson    schedule 21.12.2014
comment
gcc 4.8.3 (cygwin x64) с -std = c ++ 11 не распознает использование параметра constexpr. Это стандарт? У меня нет опыта работы с C ++ 14, но возможно ли, что constexpr-ness является свойством функции, которая может или не может быть вычислена во время компиляции, в зависимости от (неявной) constexpr-ness параметров?   -  person Peter - Reinstate Monica    schedule 21.12.2014
comment
constexpr не является квалификатором типа. Вы хотите, чтобы это было? У нас уже есть const и volatile, которые вместе дают 4 комбинации. Нам действительно нужно больше?   -  person n. 1.8e9-where's-my-share m.    schedule 21.12.2014
comment
@PeterSchneider Нет, этого нет в стандарте. OP спрашивает почему.   -  person n. 1.8e9-where's-my-share m.    schedule 21.12.2014
comment
@ n.m. Ой. Понятно. Я понял, что определение функции и вызов с аргументом 9 компилируются, но аргумент 0 не работает. Тогда я бы сказал, что было бы полезно иметь ...   -  person Peter - Reinstate Monica    schedule 21.12.2014
comment
Используя шаблоны, пользователи должны гарантировать, что литералы всегда передаются как аргументы шаблона, а не как функциональные, что очень неудобно - вы можете использовать препроцессор: #define DO_SOMETHING(...) do_something<__VA_ARGS__>()   -  person GingerPlusPlus    schedule 21.12.2014


Ответы (2)


Если я понимаю, что вы пытаетесь сделать правильно, запрошенные вами функции уже доступны. Не самый элегантный, но думаю, что этого достаточно.

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

Я верю, что это сделает то, что вы хотите:

constexpr int do_something(int x)
{
    if(x <= 0)
    {
        std::cout << "x must be > 0" << std::endl; exit(-1);
    }
    return x + 5;
}

constexpr int compiletime_good = do_something(5);
constexpr int compiletime_bad = do_something(0);    // Fails at compile-time

int runtime_good = do_something(5);
int runtime_bad = do_something(0);    // Fails at runtime

constexpr int val_good = 5;
constexpr int val_bad = 0;

do_something(val_good);
do_something(val_bad);    // Fails at run-time

int valrun_good = 5;
int valrun_bad = 0;

do_something(valrun_good);
do_something(valrun_bad);    // Fails at run-time

Хитрость здесь заключается в том, чтобы сбой во время компиляции не требовал static_assert, а также потерпел неудачу во время выполнения.

person Michael Gazonda    schedule 21.12.2014
comment
Это потребует вызова каждого экземпляра do_something там, где ожидается constexpr, что не лучше, чем использование шаблонов. - person AnArrayOfFunctions; 21.12.2014
comment
@FISOCPP Достаточно честно. Я предполагаю, что причина, по которой у нас нет явного способа включения параметров constexpr в том виде, в котором вы спрашиваете, заключается в том, что никто не удосужился написать и продвинуть предложение. Я бы хотел, чтобы это произошло, но, похоже, это требует много работы. - person Michael Gazonda; 21.12.2014
comment
Конечно, следует использовать существующее средство для сообщения об ошибке утверждения, а не разбрасывать std::exit() вызовы по всей кодовой базе. В остальном это очень хорошо. - person Ben Voigt; 21.12.2014
comment
Единственный способ улучшить его - это сделать что-то, что может вызвать предупреждение компилятора, если параметры являются константами времени компиляции, даже если они не выполняются в контексте constexpr. Может быть, целое деление на ноль? 1 / (x > 0); Конечно, то, предупреждает ли компилятор о UB, очень зависит от компилятора. - person Ben Voigt; 21.12.2014
comment
@BenVoigt Спасибо, я просто использовал код из OP, поэтому я использовал их код сбоя во время выполнения. - person Michael Gazonda; 21.12.2014
comment
@MichaelGazonda: Достаточно честно. - person Ben Voigt; 21.12.2014

Хотя в теории это звучит великолепно, в реальном мире это не так полезно. Большинство аргументов функций не являются константами времени компиляции, и многие ограничения также точно не известны во время компиляции.

Чтобы определить и реализовать такую ​​перегрузку, потребовался бы значительный объем работы, и она не использовалась бы так часто. Когда у вас действительно есть границы времени компиляции и аргументы, вы обычно можете оценить всю функцию во время компиляции, что означает, что перегрузка не требуется.

person Sebastian Redl    schedule 21.12.2014
comment
Здесь нет конкретного ответа «ПОЧЕМУ», а именно об этом и задается вопрос. - person AStopher; 21.12.2014
comment
@cybermonkey Я явно не согласен. Я попытался объяснить, почему эта функция отсутствует в стандарте, объяснив, почему она недостаточно полезна, чтобы оправдать усилия. В отличие от другого ответа на этот вопрос, который никоим образом не отвечает на вопрос «почему», в форме или форме, а просто пытается описать обходной путь (т.е. помещает фактический код, который просто демонстрирует то, что я пишу во втором абзаце). - person Sebastian Redl; 22.12.2014