2

Consider the following:

#include <type_traits>

template <typename>
struct F;

template <typename R, typename... As>
struct F<R(As...)>
{
    template <typename F_, std::enable_if_t<
        std::is_invocable_r_v<R, std::decay_t<F_>, As...>>*...>
    F(F_&&) {}

    F() = default;

    template <typename... As_, std::enable_if_t<
        std::is_invocable_v<void(As&&...), As_...>>*...>
    R operator()(As_&&...)
    { return R(); }
};

struct C
{
    F<C()> f_;

    // C(C&&) = default;  // <<< 1
};

int main() {
    F<C(int)> x;
    auto y = x;
}

gcc 7.3.0 fails to compile it (deep within std::is_invocable_r):

error: invalid use of incomplete type
    ‘struct std::__or_<std::is_void<C>, std::is_convertible<C, C> >’

as does clang 5.0.1:

error: no type named 'type' in
    'std::__or_<std::is_void<C>, std::is_convertible<C, C> >'

From this I deduce that C is missing move and copy constructors. Indeed, if we uncomment its move constructor (1), this code compiles.

I believe the requirements for them to be implicitly declared are satisfied. Why aren't they?

4

1 回答 1

2

我最好的猜测是:

F<C()> f_;

C是不完全类型。在F中,C替换模板参数R,然后将其用作 的模板参数std::is_invocable_r_v。该标准不允许使用不完整类型作为模板参数,std::is_invocable_r_v这会导致未定义的行为。除其他外,未定义的行为包括编译器在编译期间的任意行为。


请注意,我并不完全确定我的答案,主要是因为模板化的F::F构造函数和它的模板化都没有operator()被实例化。

于 2018-03-14T22:10:39.780 回答