【问题标题】:msvc is_copy_assignable always true?msvc is_copy_assignable 总是正确的?
【发布时间】:2015-02-21 14:10:21
【问题描述】:
#include <type_traits>

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

void fn(Test &a, const Test &b) { a = b; }

static_assert(!std::is_copy_assignable<Test>::value, "Test shouldn't be assignable");

在 MSVC 2013 Update 3 下编译此代码意外失败 static_assert,并且函数 fn 编译失败(如预期的那样。)这是矛盾的,对吧?

我是不是在滥用is_copy_assignable?是否有其他方法可以测试这种情况?

【问题讨论】:

  • 您的代码中的static_assert 在哪里?
  • 我正在编译的代码与这里显示的完全一样。我的原始代码使用is_copy_assignable 作为enable_if 中的参数,这是我为尝试诊断问题而创建的缩减。
  • en.cppreference.com/w/cpp/language/static_assert: "静态断言声明可能出现在块范围内(作为块声明)和类体内(作为成员声明)"
  • static_assert 是一个声明,它也可以在命名空间范围内使用。无论如何,在断言周围放置一个虚拟函数并没有帮助 - 它仍然断言。

标签: c++ visual-c++ c++11 visual-studio-2013


【解决方案1】:

你是对的,这是一个错误:https://connect.microsoft.com/VisualStudio/feedback/details/819202/std-is-assignable-and-std-is-constructible-give-wrong-value-for-deleted-members

我拿了cplusplus.com的is_copy_assignable代码:

#include <iostream>
#include <type_traits>

struct A { };
struct B { B& operator= (const B&) = delete; };

int main() {
    std::cout << std::boolalpha;
    std::cout << "is_copy_assignable:" << std::endl;
    std::cout << "int: " << std::is_copy_assignable<int>::value << std::endl;
    std::cout << "A: " << std::is_copy_assignable<A>::value << std::endl;
    std::cout << "B: " << std::is_copy_assignable<B>::value << std::endl;
    return 0;
}

并在 Visual Studio 2013 上进行了测试,得到:

is_copy_assignable:
诠释:真
答:是的
B: 是的

gcc 4.8.1 我得到了:

is_copy_assignable:
诠释:真
答:是的
B:错误

特别是在 Visual Studio 2015 Beta 上,此问题已得到修复。我明白了:

is_copy_assignable:
诠释:真
答:是的
B:错误

您对 Beta 版的感觉如何 ;)

【讨论】:

  • 谢谢,我想我必须做一些 sfinae 解决方法。 2015 年不会很快发生在我身上。
  • @TomWhittock 我链接了一个可能的副本,其中一个人提供了一个解决方法,你可能想看看。
  • 我们在工作中也做到了这一点;它有一个不同的 ms 连接 - 如果你只是将复制构造函数标记为私有(C++98 模拟删除),特征仍然返回 true;基本上没有考虑访问修饰符。
  • @StefanAtev 刚刚检查了将复制构造函数设为私有确实适用于 Visual Studio 2015 和 gcc 4.8.1。这可能并不奇怪。你们有没有想出的解决方法?这可能比“将你的编译器更新到 Beta”更好。
  • @JonathanMee - 嘿嘿;上面链接的问题是我的同事发送的;我们没有找到解决方法——我们改变了代码,所以我们不需要这个特征;我们无法通过 SFINAE 获得工作特性,所以我帮不上什么忙。
【解决方案2】:

可能有点太晚了,但我有一个解决方法:定义另一个复制和移动赋值运算符,也作为已删除的运算符。编译器发出警告,抱怨多个复制运算符(C4522),因此您必须为该类禁用它:

#pragma warning (disable: 4522)
class A
{
    A& operator=(const A&) = delete;
    A& operator=(A) = delete;
};
#pragma warning (default: 4522)

现在std::is_copy_assignable&lt;A&gt;::valuefalse

【讨论】:

  • 如果你在一个类中声明了赋值运算符,那么你不能在那里声明移动赋值运算符。这种限制使您的解决方法相当无用,因为类型特征通常用于像 std::unique_ptr 这样必须具有移动赋值运算符工作的仅移动类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-05
  • 1970-01-01
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多