【问题标题】:enable_if with is_move_constructible allows non-movable types, but requires does notenable_if 和 is_move_constructible 允许不可移动类型,但 requires 不允许
【发布时间】:2021-08-24 22:14:03
【问题描述】:

我有一个不可移动的结构和一个模板化的类,我希望在其中拥有一个仅在类型可移动时才存在的函数(使用 enable_if 和 type_traits)。但是,似乎尽管 std::is_move_constructible_v 返回 false,但该函数仍然存在并且可以执行。但是,当我将代码更改为使用 requires 子句时,一切都按预期工作。 这是为什么呢?

#include<bits/stdc++.h>

class NonMovable{
    public:
        NonMovable(const NonMovable&) = default;
        NonMovable(NonMovable&&) = delete;
        
        NonMovable& operator =(const NonMovable&) = default;
        NonMovable& operator = (NonMovable&&) = delete;
        
        NonMovable() = default;
};

template<typename T>
struct Foo{
    template<typename = std::enable_if<std::is_move_constructible_v<T>,bool>>
    void foo(T&& t){ // allowed
        // ...
    }
};

template<typename T>
struct Foo{
    void foo(T&& t) requires std::is_move_constructible_v<T>{ // not allowed
        // ...
    }
};

int main(){
    NonMovable nonMovable;
    Foo<NonMovable> x;
    std::cout << std::is_move_constructible_v<NonMovable> << "\n"; // 0
    x.foo(std::move(nonMovable));
}

【问题讨论】:

  • 看起来你的意思是enable_if_t,而不是enable_if
  • 您是否只想禁用该构造函数,而不是整个类实例?
  • @NathanPierson 谢谢你,就是这样
  • @TedLyngmo 的意图是禁用该功能。我设法用requires 子句做到了这一点。 'enable_if_t` 禁用整个班级。
  • 要使用 SFINAE 禁用 只是 成员函数而不是整个类,请查看 this question

标签: c++ templates typetraits enable-if


【解决方案1】:

如果您只想为不可移动的可构造类型禁用 foo 函数,您可以将模板参数设为依赖类型:

template<typename T>
struct Foo{
    template<class U = T, class = std::enable_if_t<
                                      std::is_same_v<T,U>&&
                                      std::is_move_constructible_v<U>>>
    void foo(T&&){ // not allowed
        // ...
    }
};

Demo

【讨论】:

  • 我认为您可能需要执行std::is_move_constructible_v&lt;std::remove_cvref_t&lt;U&gt;&gt; 或在enable_if 中包含std::is_same_v&lt;U, T&gt; 或禁用诸如允许为U = NonMovable&amp; 创建foo 之类的操作。概念和要求确实是一种进步……
  • @NathanPierson 好点。 is_same 已添加
  • 实际上,我在搞砸时遇到的问题是我签名void foo(U&amp;&amp;)而不是void foo(T&amp;&amp;),这为编译器留出了更多空间来推断@987654332的值@。尽管如此,由于其意图似乎是成员函数实际上不应与封闭结构分开模板化,因此值得锁定它的奇怪实例化。
  • @NathanPierson 我实际上不知道在foo(x&amp;&amp;) 中有UT 是否会有所不同(在我用std::is_same 添加你的想法之后).. 是否有一些极端情况这让U 更适合这里?
  • 如果你没有is_same 肯定会有所不同,但我不知道哪个更可取。实际上,我认为像您实际使用的那样使用T 更可取。我正在查看的测试调用代码是x.foo(nonMovable);,而不是x.foo(std::move(nonMovable));。使用U 而不是T 意味着它实际上已成功实例化,因为它在该上下文中U&amp;&amp; 是对左值NonMovable&amp; 的转发引用,这显然是可移动构造的。使用 T&amp;&amp; 而不是 U&amp;&amp; 似乎可以关闭它。我认为在is_same 之后并没有什么不同。
【解决方案2】:

正如评论中提到的@Nathan Pierson,应该有enable_if_t而不是enable_if

【讨论】:

    猜你喜欢
    • 2012-08-14
    • 2018-10-13
    • 2014-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多