为什么这个构造函数没有给出不完整的类型错误?

Kap*_*pil 13 c++ types language-lawyer

我有两个文件test.h和main.cpp,如下所示:

test.h

#include <memory>

class TestImpl;

template <typename... T>
void createConnection(T&&... Args)
{
    // 1. Why is this working if the constructor is in cpp?
    std::unique_ptr<TestImpl> pimpl(new TestImpl(std::forward<T>(Args)...));
    std::cout << "Done..." << std::endl;

    // 2. Why is this not working if the constructor call has no issues?
    pimpl->sayHello();
}
Run Code Online (Sandbox Code Playgroud)

main.cpp中

#include <iostream>

#include "test.h"

class TestImpl
{
public:
    TestImpl(const std::string& first, const std::string& second)
        : _first(first)
        , _second(second)
    {
    }

    void sayHello()
    {
        std::cout << "Hello ... " << std::endl;
    }

private:
    std::string _first;
    std::string _second;
};

int main()
{
    std::cout << "Hello World!" << std::endl;
    createConnection("ABC", "DEF");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

从评论中可以明显看出,我的主要问题是为什么构造函数调用没有给出错误"无效使用不完整类型'类TestImpl'......".作为参考,我使用的是GCC 5.2,没有特定的标志.

Sto*_*ica 10

简而言之,GCC不必拒绝您的程序,而且Clang不必接受它.它形成不良,无需诊断.由于TestImpl不完整,您的模板违反了

[temp.res]/8

......如果出现以下情况,该计划格式错误,无需诊断:

  • 由于不依赖于模板参数的构造,或者在其定义之后立即对模板进行假设实例化将是不正确的,或者
  • 在假设实例中对这种构造的解释不同于在模板的任何实际实例化中对相应构造的解释.

有人可能会争辩说被调用的构造函数是依赖的,但类名肯定不是!

在我们的例子中,在模板定义之后立即使用一个包两个字符串的假设实例化将给出与在程序中实例化时不同的结果.这是因为类名本身(同样,不依赖)在两个上下文中具有不同的含义.

它不是有效的模板定义.但海湾合作委员会正在这里行使一些余地,因为不需要进行诊断,而且需要继续进行.


这在子弹下的说明中简明扼要地概括,虽然不是规范性的,但描述了你的情况:

这种情况可能发生在包括以下情况:

  • 非依赖名称中使用的类型在定义模板但在执行实例化时完成时不完整,或者