在静态断言和运行时错误之间自动选择

Ami*_*nen 5 c++ static-assert visual-c++ c++11 visual-studio-2015

我有宏执行除法并检查对齐.

#define BYTES_TO_WORDS(x)  ((CHECK_ALIGNMENT(x,2)) * ((x) / 2))
Run Code Online (Sandbox Code Playgroud)

我想实现CHECK_ALIGNMENT一个总是返回1的宏,并且如果x不除以2 则触发错误.
BYTES_TO_WORDS从不同的上下文调用,有时x用作编译时常量整数表达式,有时x用作整数表达式这是在运行时解决的.

是否可以实现CHECK_ALIGNMENT,static_assert当使用常量表达式调用宏时,它将执行,并且当表达式不是编译时常量时,会检查一些运行时错误?
我可以更改宏定义,但不能更改宏的调用和使用方式.

这是一个可能的解决方案(并不总是有效):

#define CHECK_ALIGNMENT(x,alignedTo) (1/(((alignedTo)-((x)%(alignedTo)))/(alignedTo)))
Run Code Online (Sandbox Code Playgroud)

在此实现中,我们应该在运行时或编译时获得Division By Zero错误,具体取决于输入.
但是,由于编译器错误,这并不总是有效.此外,错误消息不是很好.

一个更好的解决方案是确定参数是否是编译时常量,并static_assert在这种情况下使用,编译时错误消息.如果参数不表示编译时常量,则检查运行时的对齐方式.

这可能吗?
我需要这个在Visual Studio 2015上工作.


澄清

关于为什么我在C++问题中使用宏,评论中有一些讨论.
所述BYTES_TO_WORDS宏是其中通过各种工具包括一个头文件,C++编译器是其中之一.
其他工具使用此宏并评估算术表达式((x) / 2),但在这些工具上我定义CHECK_ALIGNMENT为1,因为它们不能处理constexpr,模板甚至函数调用.
当用C++编译器编译这个头时,我想定义CHECK_ALIGNMENT一些其他东西,static_assert在需要时会触发或运行时错误.
定义CHECK_ALIGNMENT可以是任何C++ 11代码(或VS2015支持的C++ 14),可以使用模板,constexpr或诸如此类的东西.

Maa*_*lis 0

我能想到的唯一解决方案要求您在您提供的宏中使用编译时常量之前包装它们。

因此,只要您记得通过包装来正确指示编译时常量,下面的代码就会“自动”在编译时错误或运行时错误之间进行选择。int请注意,由于转换运算符,包装器也会自动转换为普通旧版本。

另外,在使用我为概念验证实现创建的类之前,请务必先查看一下Boost.Hana 。Constant下面介绍的实现不是通用的(它仅包装int并仅转换回int)并且严重缺乏功能。


#include <iostream>
#include <stdexcept>

template <int I>
struct Constant
{
    constexpr Constant() = default;

    constexpr operator int () const
    {
        return I;
    }
};

template <int I = 0>
constexpr int check_alignment(Constant<I>)
{
    static_assert(I % 2 == 0, "Error: not divisible by 2!");
    return 1;
}

int check_alignment(int value)
{
    if (value % 2 != 0)
        throw std::runtime_error("Error: not divisible by 2!");

    return 1;
}

#define CHECK_ALIGNMENT(x) check_alignment(x)
#define BYTES_TO_WORDS(x) ((CHECK_ALIGNMENT(x)) * ((x) / 2))

int main()
{
    constexpr Constant<2> c2;
    constexpr Constant<3> c3;
    constexpr Constant<4> c4;

    // Compile-time checks:
    static_assert(BYTES_TO_WORDS(c2) == 1, "Error!");
    static_assert(BYTES_TO_WORDS(c2) == 2, "Error!"); // "Error!"
    static_assert(BYTES_TO_WORDS(c3) == 2, "Error!"); // "Error: not divisible by 2!"
    static_assert(BYTES_TO_WORDS(c4) == 2, "Error!");
    static_assert(BYTES_TO_WORDS(c4) == 4, "Error!"); // "Error!"

    // Runtime checks:
    std::cout << BYTES_TO_WORDS(2) << std::endl; // outputs "1"
    std::cout << BYTES_TO_WORDS(3) << std::endl; // "Runtime error: Error: not divisible by 2!"
    std::cout << BYTES_TO_WORDS(4) << std::endl; // outputs "2"

    return 0;
}
Run Code Online (Sandbox Code Playgroud)