C++ 在编译时表达式未知时传递的静态断言

C++ 在编译时表达式未知时传递的静态断言,c++,C++,我想实现与c++17单参数static\u assert略有不同的myu static\u assert:如果编译时myu static\u assert中的条件未知,它应该通过 下面示例中的第二个my_static_assert应该通过,但是如果我使用static_assert它将失败 #include <iostream> int x, y; constexpr int f1() { return 0; } constexpr int f2() { return 0; } in

我想实现与c++17单参数
static\u assert
略有不同的
myu static\u assert
:如果编译时
myu static\u assert
中的条件未知,它应该通过

下面示例中的第二个
my_static_assert
应该通过,但是如果我使用
static_assert
它将失败

#include <iostream>

int x, y;
constexpr int f1() { return 0; }
constexpr int f2() { return 0; }
int f3() { return x; }
int f4() { return y; }
constexpr int sum(int a, int b) { return a + b; }

int main() {
    std::cin >> x >> y;

    // it should fail 
    my_static_assert(sum(sum(f1(), f2()), sum(f1(), f1())) != 0);

    // it should pass
    my_static_assert(sum(sum(f1(), f2()), sum(f4(), sum(f3(), f1()))) != 0);
}
#包括
int x,y;
constexpr int f1(){return 0;}
constexpr int f2(){return 0;}
int f3(){return x;}
int f4(){return y;}
constexpr int sum(int a,int b){返回a+b;}
int main(){
标准:cin>>x>>y;
//它应该失败
我的静态断言(sum(sum(f1(),f2()),sum(f1(),f1())!=0);
//它应该通过
我的静态断言(sum(sum(f1(),f2()),sum(f4(),sum(f3(),f1())!=0);
}
如果您想知道为什么会出现这个问题:

我正在使用叶函数f1、f2、f3、f4和表达式节点上的操作构建表达式:sum、mul、div、sub。编译时已知的叶函数包含始终为0的值


我正在尝试检查我的表达式是否至少包含一个编译时未知的元素。

如果您愿意提交给带有GNU扩展的编译器,这是可能的。因此,请注意

它需要两个重载和一个辅助宏:

template<std::size_t N>
constexpr void assert_helpr(int(&)[N]) = delete;

void assert_helpr(...) {}

#define my_static_assert(...) do {               \
    __extension__ int _tmp [(__VA_ARGS__) + 1];  \
    assert_helpr(_tmp);                          \
} while(0)
模板
constexpr void assert_helpr(int(&)[N])=delete;
void assert_helpr(…){}
#定义我的静态断言(…)do{\
__扩展名uuu int u tmp[(uu VA_ARGS_uuu)+1]\
assert_helpr(_tmp)\
}而(0)
其工作原理如下:

  • 宏获取您的标记汤,并将其视为一个整数表达式+1是避免病理零例
  • 如果表达式是常量表达式,则得到一个标准数组。否则我们会得到一个VLA
  • 现在我们调用两个重载函数中的一个。重载解析将始终最后选择一个c var arg函数。如果我们得到的是一个常规数组,则选择第一个已删除的重载,并且断言失败
  • 如果我们得到一个VLA,则选择第二个重载并通过断言
  • 我还没有对它进行彻底测试,但它似乎对Clang和GCC都有效


    非常友好地分享了基于此方法的解决方案

    下面是解决此问题的一组代码:

    template<std::size_t N>
    constexpr std::false_type assert_helpr(int(&)[N]);
    constexpr std::true_type  assert_helpr(...);
    
    #define my_static_assert(...) do {                               \
        __extension__ int _tmp[(__VA_ARGS__) + 1];                   \
        static_assert(decltype(assert_helpr(_tmp)){}, #__VA_ARGS__); \
    } while(0)
    
    模板
    constexpr std::false_type assert_helpr(int(&)[N]);
    constexpr std::true_type assert_helpr(…);
    #定义我的静态断言(…)do{\
    __扩展名uuu int u tmp[(uu VA_ARGS_uuu)+1]\
    静态断言(decltype(assert_helpr(_tmp)){}、#uu VA_ARGS_uu)\
    }而(0)
    
    重载的用法相同,除了这次我们通过
    decltype
    从调用中获取一个实际的结果类型,并继续从中创建一个真正的编译时布尔常量


    这允许直接使用
    static\u assert
    ,作为一个很好的特性,我们可以将字符串化标记传递给它,以获得失败表达式的错误指示。

    我认为这是不可能的:(中似乎有几个选项。但不确定这是否应该是一个重复。这类似于
    is_constexpr
    。有,但它得出结论,没有符合标准的方法来实现这一点。有一个版本深受此版本的启发,它使用了
    静态断言
    ,因此有一条消息:。它也有一些问题es(“代码>常量”和“编译时常量”之间的区别”)@Artyer-一点也不坏!