【问题标题】:C++ move semantics compilation error C2751C++ 移动语义编译错误 C2751
【发布时间】:2014-08-15 18:26:12
【问题描述】:

我在 MSVS2010 中用 C++11 移动语义做了一些实验,发现了一个我无法解释的编译错误。这是重现此错误的代码:

#include <iostream>
#include <memory>

struct NonCopyable
{
protected:
   NonCopyable() {}
private:
   NonCopyable( const NonCopyable& );
   NonCopyable& operator = ( const NonCopyable& );
};

struct A: private NonCopyable
{
   template< typename T >
   static std::unique_ptr< A > Create()
   {
      std::cout << __FUNCTION__ << std::endl;
      T t = T();
      return std::unique_ptr< A >( new A() );
   }
};

struct B: private NonCopyable
{
   B( std::unique_ptr< A >&& )
   {
      std::cout << __FUNCTION__ << std::endl;
   }
};

struct C: private NonCopyable
{
   C( B&& )
   {
      std::cout << __FUNCTION__<< std::endl;
   }
};

int main( int argc, char* argv[] )
{
   C c( B( A::Create< char >() ) );
   return 0;
}

尝试编译代码时收到以下错误消息:

error C2751: 'A::Create' : the name of a function parameter cannot be qualified

但是如果我像这样更改主函数,错误就会消失:

int main( int argc, char* argv[] )
{
   // I've added extra parentheses around B( A::Create< char >() )
   C c( ( B( A::Create< char >() ) ) );
   return 0;
}

你能解释一下发生了什么吗?为什么需要额外的括号?

【问题讨论】:

  • 你违反了一个简单的规则:所有可以作为函数声明的东西都是一个。
  • @Deduplicator:我还不清楚。编译器如何在字符串 C c(B(A::Create())) 中找到函数声明?
  • 嗯,MSVC 显然认为这是一个最令人头疼的解析案例,但无论是 clang 还是 gcc compile your original example successfully,所以可能这是一个 MSVC 的错误。仔细观察,我很难想出这是 MVP。 A::Create&lt;char&gt; 不是类型,所以 A::Create&lt;char&gt;() 不能衰减为 A::Create&lt;char&gt;(*)()
  • @Praetorian:感谢您提供有用的链接。我对主函数进行了一些更改: typedef std::unique_ptr (*Ptr)(); ptr ptr = &A::Create; C c( B( ptr() ) );现在我收到了这个警告:warning C4930: 'C c(B (__cdecl *)(void))':prototyped function not called (是一个变量定义吗?)

标签: c++ visual-studio-2010 c++11 compiler-errors


【解决方案1】:

MVP 就是这样 (Most vexing parse)

让我们重写 main 函数以更清晰:

int main( int argc, char* argv[] )
{
   typedef std::unique_ptr< A > (*Ptr)();
   Ptr ptr = &A::Create< char >;
   C c( B( ptr() ) );
   return 0;
}

编译器何时会输出详细的警告信息:

warning C4930: 'C c(B (__cdecl *)(void))': prototyped function not called (was a variable definition intended?)

编译器将 B( ptr() ) 视为普通函数声明,如下所示:

int ( foo() )
{
   return 1;
}

这就是为什么使用额外的括号有助于避免编译错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-14
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多