C++ Googletest不接受EXPECT\u抛出中的临时对象

C++ Googletest不接受EXPECT\u抛出中的临时对象,c++,g++,googletest,C++,G++,Googletest,我有一个没有默认构造函数的类,但是构造函数可能抛出。我想做一个测试,比如: EXPECT_THROW(MyClass(param), std::runtime_error); 但是编译器g++,抱怨MyClass没有默认构造函数。然而,以下 EXPECT_THROW(MyClass foo(param), std::runtime_error); …工作正常,测试按预期通过。为什么Googletest不接受临时对象 class MyClass { public: MyClass(std:

我有一个没有默认构造函数的类,但是构造函数可能抛出。我想做一个测试,比如:

EXPECT_THROW(MyClass(param), std::runtime_error);
但是编译器
g++
,抱怨
MyClass
没有默认构造函数。然而,以下

EXPECT_THROW(MyClass foo(param), std::runtime_error);
…工作正常,测试按预期通过。为什么Googletest不接受临时对象

class MyClass
{
public:
  MyClass(std::string const& filename);
  //...
};
有趣的是,我对测试进行了重构,使文件名不在单独的变量中,当被要求检查时,我发现以下方法可行:

EXPECT_THROW(MyClass("somefilename"), std::runtime_error);
但是,以下情况并非如此:

std::string filename("somefilename");
EXPECT_THROW(MyClass(filename), std::runtime_error);

你能提供更多的信息吗?我构造了一个示例,它可以很好地处理只有一个参数构造函数的类

#include <iostream>
#include <stdexcept>

#include "gtest/gtest.h"

class m {
    public:
        m(std::string a) {std::cout << "one argument constructor" << std::endl;}
};

int main() {
    EXPECT_THROW(m("hat"), std::runtime_error);
}
编辑
我并不声称自己是C/C++预处理器神秘内部工作原理方面的专家,但我认为这与计算表达式时遵循的规则有关,特别是在预处理器领域,括号为王。当预处理器计算
MyClass(filename)
时,它首先计算filename,该filename生成一个临时值,该临时值将立即被丢弃,然后计算
MyClass()
。调用
MyClass(“filename”)
会导致预处理器将文本字符串实际复制到表达式中。解决此问题的一种方法是调用
EXPECT\u THROW((MyClass(filename)),std::runtime\u error)
,即在语句周围使用一组圆括号。

处理宏时,终极工具是分析扩展宏:

在您的情况下(对于gtest 1.6):

扩展到:

...
    bool gtest_caught_expected = false; \
    try { \
      if (::testing::internal::AlwaysTrue()) { MyClass(filename); }; \
    } \
    catch (std::runtime_error const&) { \
      gtest_caught_expected = true; \
    } \
    catch (...) { \
      gtest_msg.value = \
          "Expected: " "MyClass(filename)" " throws an exception of type " \
          "std::runtime_error" ".\n  Actual: it throws a different type."; \
      goto gtest_label_testthrow_88; \
    } \
    if (!gtest_caught_expected) { \
      gtest_msg.value = \
          "Expected: " "MyClass(filename)" " throws an exception of type " \
          "std::runtime_error" ".\n  Actual: it throws nothing."; \
      goto gtest_label_testthrow_88; \
    } \
...
如您所见,
EXPECT_THROW
的参数不是object,而是要在GTEST提供的有效try/catch块中进一步计算的表达式

所以,传递给它的任何内容都必须能够在当前范围的嵌套范围内作为表达式进行计算。就你而言:

MyClass(filename)
是不明确的,但根据最令人烦恼的解析规则,声明解释是首选的,因此您最终会得到:

MyClass filename
所以,您正在创建名为MyClass类的filename的变量,从而导致缺少构造函数的错误

#include <iostream>
#include <stdexcept>

#include "gtest/gtest.h"

class m {
    public:
        m(std::string a) {std::cout << "one argument constructor" << std::endl;}
};

int main() {
    EXPECT_THROW(m("hat"), std::runtime_error);
}
如果使用文字字符串,则不会触发此机制:

MyClass("some string")
因为以下内容无效(且不存在歧义):

如果遇到“最麻烦的解析”,解决方法通常是统一初始化:

EXPECT_THROW(MyClass{param}, std::runtime_error);

(假设您的编译器理解C++11)。

Ha。。。这不是很奇怪吗。我去复制它,我发现我的重构导致它没有发生。然而,当我重新进行重构时,我发现了错误。我将添加上面的细节。在我的帖子中添加了一个暂定答案,即如果MyClass接受超过1个参数,则需要一组额外的括号,因为EXPECT_THROW是一个宏:
EXPECT_THROW((MyClass{param1,param2}),std::runtime_error)
MyClass "some string"
EXPECT_THROW(MyClass{param}, std::runtime_error);