C ++ 14中noexcept指定符的奇怪行为

问题描述 投票:5回答:1

我在C ++ 14中发现了noexcept运算符的奇怪行为。以下代码可以通过gcc和clang很好地编译(使用--std = c ++ 14选项)。

// test.cpp
#include <iostream>
#include <type_traits>

#if 1
#define TESTREF(X) X&&
#else
#define TESTREF(X) X const&
#endif

template <class F, class... Args>
struct is_noexcept_callable
    : public std::conditional_t<noexcept(std::declval<F>()(std::declval<Args>()...)), std::true_type, std::false_type> {};

template <
    class F,
    std::enable_if_t<is_noexcept_callable<F,int>::value,int> = 0
    >
int evalInt(int x, TESTREF(F) f) noexcept
{
    return static_cast<int>(f(x));
}

template <
    class F,
    std::enable_if_t<!is_noexcept_callable<F,int>::value,int> = 0
    >
int evalInt(int x, TESTREF(F) f)
{
    return static_cast<int>(f(x));
}

int id(int x) noexcept { return x; }
int thrower(int x) { throw(0); }

int main(int argc, char* argv[])
{
    std::cout << std::boolalpha
              << noexcept(evalInt(1,id))
              << std::endl;
    std::cout << std::boolalpha
              << is_noexcept_callable<decltype(thrower), int>::value
              << std::endl;
}

执行结果程序,但是根据编译器,我得到了不同的结果:

$ g++ --std=c++14 test.cpp
$ ./a.out
true
false
$ clang++ --std=c++14 test.cpp
$ ./a.out
false
false

我不确定根据标准哪个是正确的。

更奇怪的是,如果我将上面代码中的第5行更改为#if 0,则gcc将代码编译为另一个不同的程序:

$ ./a.out
true
true

如您所见,第二个值已更改。但是,它仅取决于宏不触摸的noexcept功能的thrower规格。是否对此有任何合理的解释,还是仅仅是一个错误?

c++ c++14 language-lawyer noexcept
1个回答
0
投票

我只能在版本8之前的GCC中重现此错误。行为上的差异是由于noexcept说明符是GCC 7的C ++ 14版本(但不是Clang的)中函数类型的一部分,尽管这是一个C ++ 17功能。如果我们添加is_noexcept_callable的部分专业化,则可以看出这一点:

template <class... Args>
struct is_noexcept_callable<int(&)(int), Args...>
    : public std::false_type {};

template <class... Args>
struct is_noexcept_callable<int(int), Args...>
    : public std::false_type {};

此突然出现yields two falses:GCC保留了函数类型的false属性,但明确地在模板参数推导过程中忽略它们

,因此尽管忽略了错误消息,但仍显示noexcept定义:
noexcept
© www.soinside.com 2019 - 2024. All rights reserved.