(为什么)这是一个令人烦恼的解析的例子吗?

时间:2017-01-26 02:01:22

标签: c++ most-vexing-parse

这是C ++中一个令人烦恼的解析的例子吗?

#include <pthread.h>
#include <iostream>

class ScopeLock
{
public:
  ScopeLock(pthread_mutex_t& m)
    : mrMutex(m)
  {
    pthread_mutex_lock(&mrMutex);
  }

  ~ScopeLock()
  {
    pthread_mutex_unlock(&mrMutex);
  }

protected:
  pthread_mutex_t& mrMutex;
};

class Foo
{
public:
  Foo()
  {
    pthread_mutex_init(&m_, NULL);
  }

  ~Foo()
  {
    pthread_mutex_destroy(&m_);
  }

  void Func()
  {
    ScopeLock(m_); // Is this a vexing parse?
    std::cout << __FUNCTION__ << std::endl;
  }

protected:
  pthread_mutex_t m_;
};

int main(int argc, char* argv[])
{
  Foo foo;
  foo.Func();

  return 0;
}

输出:

>g++ main.cpp 
main.cpp: In member function \u2018void Foo::Func():
main.cpp:37:17: error: no matching function for call to 'ScopeLock::ScopeLock()'
     ScopeLock(m_);
                 ^
main.cpp:37:17: note: candidates are:
main.cpp:7:3: note: ScopeLock::ScopeLock(pthread_mutex_t&)
   ScopeLock(pthread_mutex_t& m)
   ^
main.cpp:7:3: note:   candidate expects 1 argument, 0 provided
main.cpp:4:7: note: ScopeLock::ScopeLock(const ScopeLock&)
 class ScopeLock
       ^
main.cpp:4:7: note:   candidate expects 1 argument, 0 provided

我认为编译器失败是因为它试图创建一个没有ctor参数的ScopeLock对象(名为m_),并且正确地识别出唯一的ScopeLock ctor只需要一个pthread_mutex_t&争论 - 这是正确的吗?

为什么这是一个令人烦恼的解析,但是(如果是的话)?为什么第37行不被解释为使用ctor参数ScopeLock创建匿名m_对象?

如果以上是一个令人烦恼的解析的例子,为什么以下不是一个令人烦恼的解析?

#include <iostream>
#include <string>

class Foo
{
public:
  Foo()
  {
    pStr = "Foo";
  }

  ~Foo()
  {
  }

  void Func()
  {
    const std::string& rStr = std::string(pStr);
    std::cout << rStr << std::endl;
  }

protected:
  const char* pStr;
};

int main(int argc, char* argv[])
{
  Foo foo;
  foo.Func();

  return 0;
}

编译和输出:

>g++ main.cpp
>./a.out
Foo
>

第二个代码块似乎与第一个类似。为什么,编译器不会将第18行视为创建名为std::string且没有ctor参数的pStr?导致“Foo”的cout rStr实际上显示使用std::string参数创建了匿名const char*

如果有人能在这里阐明,我将不胜感激。谢谢。

更新 我刚刚注意到在第一个代码块中改变了这个:

ScopeLock(m_); // Is this a vexing parse?

到此:

const ScopeLock& rSl = ScopeLock(m_); // Is this a vexing parse?

导致编译传递。那么将匿名对象转换为右值的问题可以解决棘手的解析问题?我不清楚。

另一方面,在第二个代码块中,更改此:

const std::string& rStr = std::string(pStr);

到此:

std::string(pStr);

编译得很好。但是,cout生成的pStr为空。我认为这证实了编译器实际上是使用默认构造函数创建名为std::string的{​​{1}}。实际上,这类似于它在第一个代码块中尝试做的事情。

如果有人能确认我推测的是否正确,我仍然会感激不尽。

3 个答案:

答案 0 :(得分:2)

  

为什么第37行不会被解释为使用ctor参数ScopeLock创建匿名m_对象?

这是因为标准规则规定,如果代码具有可以解释为声明或函数调用的结构,则选择处理作为声明。

它并不担心治疗作为声明是否会在以后导致错误。

如果你考虑一下,对一个完全不同的解释进行回退会在代码维护期间导致一些非常令人讨厌的远距离行动结果。想象一下,如果您编写此代码并且它被接受为函数样式转换,后来有人添加了默认构造函数...

答案 1 :(得分:2)

&#34;规范&#34; &#34; most vexing parse&#34;的含义指的是对象声明和函数声明之间的歧义。

在你的案例中你有一个不同的歧义:对象声明和功能样式演员之间的歧义(更正式地说:显式类型转换的功能表示法,见5.2.3)。后一种歧义的解决有利于对象声明。因此错误。您的代码被编译器视为一个简单的

ScopeLock m_;

这使得它抱怨缺少默认构造函数。

  

6.8歧义解决[stmt.ambig]

     

1 语法中涉及表达式语句和声明的含糊不清:带有函数式显式类型转换(5.2.3)的表达式语句,因为它最左边的子表达式可以与a无法区分第一个声明符以a开头的声明(。在这些情况下,声明是声明。

你是否想把它称为另一种最令人烦恼的解析&#34;由你决定。

有许多不同的方法可以让编译器将其解释为表达式而不是声明。你也可以这样做

0, ScopeLock(m_);

(ScopeLock(m_));

答案 2 :(得分:0)

尝试更换 ScopeLock(m_);ScopeLock s(m_);。该对象需要它的名字。

-

也许编译器将ScopeLock(m_)视为ScopeLock m_。我用clang编译,它显示了类似的错误信息。

以下行编译没有任何投诉:

void Func()
{
  ScopeLock(m)(m_);
  std::cout << __FUNCTION__ << std::endl;
}