c ++从decltype返回类型中删除noexcept

时间:2017-08-30 16:24:37

标签: c++ template-meta-programming c++17 decltype

#include <functional>
#include <sys/types.h>
#include <sys/socket.h>


std::function<decltype(::bind)> mockbind = ::bind;

int main()
{
}

上面的代码适用于我编译的大多数平台。但是在使用g ++ - 7的ubuntu 14.04上我收到一个错误:

X.cpp:7:65: error: variable ‘std::function<int(int, const sockaddr*, unsigned int) noexcept> mockbind’ has initializer but incomplete type
 std::function<int(int, const sockaddr*, unsigned int) noexcept> mockbind = ::bind;
                                                                 ^~~~~~~~

现在,如果我手动去改变mockbind

的类型
std::function<int(int, const sockaddr*, unsigned int) noexcept> mockbind = ::bind;

正如所料,我得到了同样的错误:
现在,如果我删除noexcept

std::function<int(int, const sockaddr*, unsigned int)> mockbind = ::bind;

按预期编译。

所以问题是我可以应用一些模板代码从noexcept返回的类型中删除decltype并使其按预期工作。

2 个答案:

答案 0 :(得分:12)

一个简单的类专门化技巧应该有效:

template <typename T> struct remove_noexcept
{
    using type = T;
};
template <typename R, typename ...P> struct remove_noexcept<R(P...) noexcept>
{
    using type = R(P...);
};
template <typename T> using remove_noexcept_t = typename remove_noexcept<T>::type;

// ...

std::function<remove_noexcept_t<decltype(::bind)>> mockbind = ::bind;

您可以在某种程度上轻松扩展它以从[成员]函数指针中删除noexcept,这将作为阅读器的左侧。

如果您希望在没有using type = T;的情况下获得编译时错误而不是保持类型不变,则可以注释掉noexcept

答案 1 :(得分:0)

虽然HolyBlackCat的答案涵盖了大多数实际用例,但它无法涵盖许多可能的情况,包括qualified function type(例如int(int) const noexcept),可变参数化可变参数函数(例如{{ 1}})和指向成员函数的指针(这些成员函数完全不在常规的 pointer 规则下运行,例如template<typename... Ts> void foo(Ts..., ...) noexcept)。

实现涵盖所有这些极端情况的int(foo::*)(int) noexcept特征并不是一件容易的事,但这是我的责任。我用remove_noexcept来实现remove_noexcept_t,它的第二个参数允许您切换结果make_noexcept_t<T, bool>的状态(如您所愿,noexceptnoexcept(true)

值得注意的是,此可以用于指向成员函数的指针,但不能可以用于函数指针。这是设计使然(主要遵循noexcept(false)的逻辑),尽管您可以很容易地像std::is_pointer那样建立using声明。

Live Demo更新

编辑:在发布此内容之前,未使用MSVC ++ 2019(v142)对以下实现进行准确性测试。尽管它可以与GCC和Clang一起使用,但此实现对MSVC ++ 2019(v142)不能起作用。实时演示链接已更新为更长的时间实现(专业化程度的两倍),太长了,无法发布到StackOverflow。该实现已在GCC,Clang和MSVC ++ 2019(v142)中进行了测试。

add_pointer_t<make_noexcept_t<remove_pointer_t<decay_t<T>>>>