如何防止constexpr功能的意外发射

Vor*_*rac 2 constexpr c++14

Ben Deane提到了throw技巧,它确保在非constexpr上下文中使用constexpr函数时出现链接错误.

这是我的看法:

#include <iostream>

struct Exc;

constexpr int foo( int a )
{
    if( a == 42 )
    {
        throw Exc{};
    }

    return 666;
}


int main()
{
    constexpr auto ret = foo(43);
    std::cout << ret << "\n";

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

但我无法使它工作(clang ++ 3.8.1-23和g ++ 6.3.0):

$ clang++ -std=c++14  main.cpp 
main.cpp:9:15: error: invalid use of incomplete type 'ExcBase'
        throw ExcBase{};
              ^~~~~~~~~
main.cpp:3:8: note: forward declaration of 'ExcBase'
struct ExcBase;
       ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

这个帖子中的评论暗示了另一个技巧:

#include <iostream>

constexpr int foo( int a )
{
    if( a == 42 )
    {
        (void)reinterpret_cast<int>(a);
    }

    return 666;
}

int main()
{
    constexpr auto ret = foo(43);
    std::cout << ret << "\n";

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

哪个有效:没有错误或警告; 当调用替换为foo(42),clang返回:

$ clang++ -std=c++14 main.cpp 
main.cpp:19:20: error: constexpr variable 'ret' must be initialized by a constant expression
    constexpr auto ret = foo(42);
                   ^     ~~~~~~~
main.cpp:10:15: note: reinterpret_cast is not allowed in a constant expression
        (void)reinterpret_cast<int>(a);
              ^
main.cpp:19:26: note: in call to 'foo(42)'
    constexpr auto ret = foo(42);
                         ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

哪个好.但是gcc在这两种情况下都很愉快地编译代码.而现在的问题.如何以这样的方式编写constexpr函数,它不能在非constexpr环境中使用?

mar*_*inj 5

问题是你实际上实例化(调用构造函数)一个类型不完整的结构.你谈到的这个技巧需要在链接时找不到任何符号.所以struct你可以使用int:

http://coliru.stacked-crooked.com/a/3df5207827c8888c

#include <iostream>

extern int Exc;

constexpr int foo( int a )
{
    if( a == 42 )
    {
       throw Exc;
    }

    return 666;
}


int main()
{
    // Compiles
    constexpr auto ret = foo(43);
    std::cout << ret << "\n";

    // This will show linker error as expected:
    // /tmp/ccQfT6hd.o: In function `main':
    // main.cpp:(.text.startup+0x4c): undefined reference to `Exc'
    // collect2: error: ld returned 1 exit status
    int nn;
    std::cin >> nn;
    auto ret2 = foo(nn);

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