C++ 编译时强制constexpr函数求值的单表达式帮助器是否可能?

C++ 编译时强制constexpr函数求值的单表达式帮助器是否可能?,c++,c++11,macros,variadic-templates,constexpr,C++,C++11,Macros,Variadic Templates,Constexpr,正试图取得一些成就,并就此提出了一些问题,但所有的追逐归结为以下几点: 是否可以构建一个工具来强制执行constepr函数的编译时计算 int f(int i) {return i;} constexpr int g(int i) {return i;} int main() { f(at_compilation(g, 0)); int x = at_compilation(g, 1); constexpr int y = at_compilation(g, 2); }

正试图取得一些成就,并就此提出了一些问题,但所有的追逐归结为以下几点:

是否可以构建一个工具来强制执行
constepr
函数的编译时计算

int f(int i) {return i;}
constexpr int g(int i) {return i;}

int main()
{
    f(at_compilation(g, 0));
    int x = at_compilation(g, 1);
    constexpr int y = at_compilation(g, 2);
}
在所有情况下,
at_编译
强制编译时计算
g

at_编译
不需要采用这种形式

要求
  • 允许任何(数字本机)文字类型作为constexpr函数的输入。
    • 这也可以基于函数参数类型进行硬编码
  • 允许任何(数字本机)文本类型作为输出,这是constexpr函数调用的结果。
    • 也可以根据函数返回类型对其进行硬编码
可取的
  • 减少了宏的使用,但不要害怕使用
  • 一般(非硬编码类型)
  • 支持任何文本类型。最后,需要任何数字本机文字类型
相关问题:
  • 相关代码示例的答案:
    • (这个有一个说明性的
      AT_编译
      macro)
    所有代码示例都有关于需求的限制

    <对C++中不可行的解释是一个很好的答案。

    我怀疑这是不可能的,因为“结果也用于常量表达式”。这不是我以前关于
    constexpr
    函数的概念的一部分,我首先认为,仅仅传递文本(或其他编译时输入)作为参数就足以保证(按照标准)在编译时对其进行评估


    我们已经假设constexpr函数的目的是在必要时,它们可以适应常量表达式的情况,比如数组边界。没关系。考虑到这一点,这个问题是关于使用它们作为编译时计算工具的一个技巧。做这件事是好是坏应该无关紧要。

    我认为这是不可能的,因为编译器只需要计算编译时使用的值,并且没有通用表达式可以使用类类型值的每个部分。初始化私有成员的计算甚至可能无法强制执行,因为您将依赖公共constexpr成员函数来使用结果

    如果可以通过以下方式访问对象表示:

    static_cast< char const * >( static_cast< void const * >( & const_value ) )
    
    如果不想修复结果值,则放弃它们。(不幸的是,GCC是这样一个表达的一部分,所以你可能需要在这个平台上做一些更巴洛克的事情

    static_assert( g( i ) == 5 || true, "failure only if not constexpr" );
    

    至于将其封装到宏中,其他相关问题似乎解决了很多问题。如果您想扩展其中一个答案或修复某个特定错误,最好解释该错误,而不是要求我们阅读大量文献并从头开始。

    使用
    std::integral_constant

    int x = std::integral_constant<int, g(0)>::value;
    f(std::integral_constant<int, g(1)>::value);
    
    intx=std::integral\u常量::值;
    f(标准:积分常数:值);
    
    如果在编译时不计算g(n),此代码将不会编译。

    多亏了C++17(lambda constexpr,auto-template参数,内联为有效的模板非类型值),我们现在有了一个解决方案:

    //implementation
    #include <utility>
    
    template<auto X>
    using constant = std::integral_constant<decltype(X), X>;
    
    template<class T>
    constexpr auto to_constant(T f) //should use && but clang has a bug that would make +f fail
    {
       constexpr auto ptr = +f; //uses conversion operator to function pointer
       return constant<ptr>{}; //not yet implemented for gcc ("no linkage"), working with clang
    }    
    
    #define constexpr_arg(...) to_constant([]{ return __VA_ARGS__; })
    
    //userland
    template<auto Func>
    constexpr void func(constant<Func>)
    {
       constexpr decltype(auto) x = Func();
       static_assert(x == 3.14);
    }
    
    int main()
    {
       func(constexpr_arg(3.14));
    }
    
    //实现
    #包括
    模板

    此外,此版本并不适用于所有情况(主要是在宏的参数使用非constexpr值但仍生成constexpr结果时)

    对于此类使用情况:

    对于gcc版本(目前可移植):

    //实现
    模板
    结构常数
    {
    静态constexpr decltype(auto)value=T::getPtr();
    };
    模板
    constexpr auto to_constant(T&&f)//如果希望与clang兼容,请删除&&
    {
    constexpr auto ptr=+f;//将转换运算符用于函数指针
    结构A
    {
    静态constexpr auto getPtr(){return ptr;}
    };
    
    在编译时,不仅要基于它的参数,还要根据它使用的上下文,在C++中没有上下文相关的表达式。对于任何声称的编译时常量整数表达式<代码>()(代码)>,您总是可以使用<代码> TyPulf char哑[f]();
    然后获取值为
    sizeof(dummy)
    std::extent::value
    @KerrekSB:该值必须为正…@aschepler:这是真的。我想添加适当的强制转换,包括
    make_unsigned
    decltype
    可以解决该限制……即使编译器在编译时对表达式求值,通常也允许在编译时对其重新求值运行时(为了好玩,每隔一条指令检查一次2+2!=3)。虽然它有一些可能对实际问题有影响的点,但我发现它有很多不重要的点。我看到了太多的东西,没有直接从可能出现问题的地方解决问题(考虑到存在的所有约束).这是唯一重要的事情(最后对我来说,我也严格地猜测)。@chico 1.这个问题只有在我们定义什么是“功能评估”时才有意义意思是。在这种情况下,这意味着使用一个函数计算的所有值。2.我们可以使用类类型的对象包含的所有值吗?3.运行时有效的策略在编译时无效。4.没有更多的可能性;这是不可能的。-如果您觉得有什么问题没有答案,或者有更多问题,请询问。如果您看到要缩短此答案的快捷方式,请编写您自己的答案。
    constepr
    函数的用途是什么?它们在运行时和编译时都适用,这是一种策略,可用于在运行时初始化普通变量以及初始化数组大小,前提是您知道适用于参数的约束条件。Th问题是这样的,结构
    //implementation
    #include <utility>
    
    template<auto X>
    using constant = std::integral_constant<decltype(X), X>;
    
    template<class T>
    constexpr auto to_constant(T f) //should use && but clang has a bug that would make +f fail
    {
       constexpr auto ptr = +f; //uses conversion operator to function pointer
       return constant<ptr>{}; //not yet implemented for gcc ("no linkage"), working with clang
    }    
    
    #define constexpr_arg(...) to_constant([]{ return __VA_ARGS__; })
    
    //userland
    template<auto Func>
    constexpr void func(constant<Func>)
    {
       constexpr decltype(auto) x = Func();
       static_assert(x == 3.14);
    }
    
    int main()
    {
       func(constexpr_arg(3.14));
    }
    
    //implementation
    template<class T>
    struct constant
    {
       static constexpr decltype(auto) value = T::getPtr()();
    };
    
    template<class T>
    constexpr auto to_constant(T&& f) //remove the && if you want to be also compatible with clang
    {
       constexpr auto ptr = +f; //uses conversion operator to function pointer
       struct A
       {
          static constexpr auto getPtr() { return ptr; }
       };
       return constant<A>{};
    }    
    
    #define constexpr_arg(...) to_constant([]{ return __VA_ARGS__; })
    
    //userland
    template<class Constant>
    constexpr void func(Constant&&)
    {
       static_assert(Constant::value == 3.14);
    }
    
    int main()
    {
       func(constexpr_arg(3.14));
    }