is_constant_evaluated() должен создавать переменные constexpr?

Я прочитал определение std::is_constant_evaluated(), но до сих пор не понимаю, почему (1) не работает с последней версией GCC: error: 'x' is not a constant expression

template<auto v>
struct s
{};

constexpr void f(int x)
{
    if (std::is_constant_evaluated())
    {
        // constexpr int z=x; (1)
        // s<x> a; (2)
    }
}

int main(int argc, char* argv[])
{
    f(4);
    //f(argc);
    return 0;
}
  1. По стандарту это должно работать?
  2. Или просто реализация GCC глючит?
  3. Как-то я могу добиться ожидаемого поведения? Что в основном:

С ответвлением на std::is_constant_evaluated()

  • если это правда: код может использовать переменные как constexpr (например, (2))
  • если ложно: код использует переменные как неконстансные

ОБНОВЛЕНИЕ

Могу ли я «перенести» информацию о контексте в функцию? В принципе решать в f() был ли это вызов с constexpr x или нет.

ОБНОВЛЕНИЕ Более сложный пример того, чего я хотел бы достичь: этот образец должен, если возможно, преобразовать параметр в строку во время компиляции.

template<auto v>
struct dummy_stringify
{
    static constexpr auto str=v==4 ? "4" : "31"; // this is just an example; imagine here a much more complex logic
};

constexpr void f(int x)
{
    if (std::is_constant_evaluated())
    {
        std::puts("A compile time calculation:");
        //std::puts(dummy_stringify<x>::str);
    } else
    {
        std::cout<<"A runtime calculation:"<<std::endl;
        std::cout<<x<<std::endl;
    }
}
int main(int argc, char* argv[])
{
    f(4);
    f(argc);
    return 0;
}

person Balázs Árva    schedule 13.08.2019    source источник
comment
прочитайте это: stackoverflow.com/questions/54251530/   -  person Gupta    schedule 13.08.2019
comment
Расскажите подробнее об ожидаемом поведении и почему вы хотите его добиться. Может быть вообще другая альтернатива.   -  person StoryTeller - Unslander Monica    schedule 13.08.2019
comment
@StoryTeller Я добавил более сложный пример. У меня есть решение: если бы я обернул параметр f(wrap<4>);, я смог бы перегрузить f() для этого типа переноса... Но я хотел бы унифицировать поведение в одной функции, если это возможно   -  person Balázs Árva    schedule 13.08.2019
comment
Вы хотели использовать if constexpr?   -  person rubenvb    schedule 13.08.2019
comment
@BalázsÁrva - боюсь, у С++ пока нет средств для его унификации, насколько мне известно.   -  person StoryTeller - Unslander Monica    schedule 13.08.2019
comment
if constexpr (std::is_constant_evaluated()) всегда верно. Думаю в принципе бессмысленно его использовать. Или if constexpr () что?   -  person Balázs Árva    schedule 13.08.2019


Ответы (3)


x не является постоянным выражением, независимо от того, как оценивается само f. Это обычный if прямо здесь (как предполагается использовать is_constant_evaluated). Это не отброшенная ветвь, поэтому она должна содержать корректный код, даже если f не оценивается как константа. Когда x не будет постоянным выражением, функция по-прежнему будет содержать эту (неисполненную) ветвь и попытается использовать x там, где требуется постоянное выражение. Это просто плохо сформировано.

GCC очень правильно не принимает его.

person StoryTeller - Unslander Monica    schedule 13.08.2019
comment
Спасибо, я добавил обновление на основе вашего ответа. Но, как я вижу, вы ответите на этот вопрос определенно НЕТ. Я прав? - person Balázs Árva; 13.08.2019
comment
@BalázsÁrva - Насколько я вижу. Но, возможно, я недостаточно понимаю вашу цель, чтобы утверждать обратное. - person StoryTeller - Unslander Monica; 13.08.2019

Фундаментальная проблема здесь заключается в том, что даже при вызове функции constexpr (или даже consteval) во время постоянного вычисления (и при проверке is_constant_evaluated) остается только одна функция, совместно используемая всеми значениями аргументов. Поэтому вы не можете никогда использовать параметр функции в качестве константного выражения (даже если вызов с этим параметром является константным выражением). Если вам нужен параметр постоянного выражения, он должен быть параметром шаблона.

person Davis Herring    schedule 13.08.2019

ОБНОВИТЬ

Я нашел решение с небольшим вспомогательным классом (конечно, можно использовать std::integral_constant)

template<auto val_>
struct val
{
    static constexpr auto value=val_;
};

template<auto v>
struct dummy_stringify
{
    static constexpr auto str=v==4 ? "4" : "31"; // this is just an example; imagine here a much more complex logic
};

#include <iostream>
using namespace std;

template<class T>
constexpr void f(T x)
{
    if constexpr(requires{ T::value; })
    {
        std::puts("A compile time calculation:");
        std::puts(dummy_stringify<T::value>::str);
    } else
    {
        std::cout<<"A runtime calculation:"<<std::endl;
        std::cout<<x<<std::endl;
    }
}
int main(int argc, char* argv[])
{
    f(val<4>{});
    f(argc);
    return 0;
}

Его можно улучшить с template<char...> auto operator""_v(); до f(4_v)

person Balázs Árva    schedule 27.09.2019