noexcept 对于函数内部模板类型的不同操作

noexcept for different operations with template type inside function

我想写一个模板函数 foo,对类型 T 做一些操作,在这个函数中类型 T 的值可以是:

所以,我需要为这个函数指定 noexcept,并带有我上面提到的限制。

这是我的代码,但它不能正常工作:

template<class T>
void foo() 
    noexcept(noexcept(std::declval<T>() + std::declval<T>()) && std::is_copy_constructible<T>::value && std::is_assignable<T, T>::value)
{}

bool b1 = noexcept(foo<int>()); // false, but should return true
bool b2 = noexcept(foo<std::string>()); // false

我应该怎么做才能让它正常工作?

noexcept(foo<int>()); 为假,因为 std::is_assignable<int, int>::value 为假,例如你不能写 1 = 1。您可能想要做的是改用 std::is_assignable<T&, T>

问题出在您的 std::is_assignable<int, int>(即 false)。您通常不能分配给 int,只能分配给 int&(即左值引用,这意味着存在您正在修改的实际对象)。如果没有引用限定符,右值也必须是可分配的(例如语句 1=1 必须有效)。

因此,将 T 更改为 std::is_assignable 表达式中的 T&

您尝试用 noexcept() 检查 T operator+(T,T) 是否存在,但这只会检测到 noexcept operator+。在我看来,我们可以做得更好。

namespace detail
{
    template<class>
    struct sfinae_true : std::true_type{};

    template<class T>
    static auto can_add(int) -> sfinae_true<decltype(std::declval<T>() + std::declval<T>())>;

    template<class>
    static auto can_add(long) -> std::false_type;
}
template<class T>
struct can_add : decltype(detail::can_add<T>(0))
{};

这定义了一个特征来检查,对于给定的类型 T,表达式 T{}+T{} 是否有意义。

测试用例:

struct s1 {};
s1 operator+(s1,s1) { return s1{}; }

struct s2 {};
s2 operator+(s2 const&, s2 const&) { return s2{}; }

struct s3 {};

#include <iostream>
int main()
{
    std::cout << can_add<s1>::value << "\n"; // true
    std::cout << can_add<s2>::value << "\n"; // true
    std::cout << can_add<s3>::value << "\n"; // false
}

然后您可以定义:

template<class T>
struct is_foo_compatible : std::conjunction<
    can_add<T>,
    std::is_copy_constructible<T>,
    std::is_assignable<T&, T>
> {};

它就是有效™。