0

给定一个模板成员函数(......模板化类中的模板化构造函数,碰巧)采用可变参数通用引用,以及另一个候选函数(复制构造函数,在我的例子中),GCC和clang都选择通用引用模板复制对象时的重载决议。由于两个完全不同的编译器行为相同,我会假设这确实是“正确的事情”。https://godbolt.org/g/mip3Fi
上 的示例代码。

因此,当复制时,有两个具有相同数量参数的可行候选函数,两者都具有完美匹配(在模板版本的引用折叠之后),其中一个是候选函数模板特化,另一个不是. 当然,其中调用一个是“显然需要”,而调用另一个则不是。

我对重载决策的理解是,在候选函数集合中,要选择最佳可行的候选者,如果等效可行的模板和非模板候选者竞争,则选择非模板候选者。那将是复制构造函数。

显然,编译器(可能是标准?)的想法不同。这个相当不明显的例外的理由是什么?

奖金问题:

如何防止这种情况发生,即如何告诉编译器我真的想在制作副本时调用复制构造函数?

诸如消除不良候选者之类的东西enable_if_t<!is_same<container<T> const& blahblah...> blah>,并按预期复制工作,但是该方法并没有太大帮助,因为当您使用多个参数调用可变参数模板时,它将无法编译(这是它的原始目的!)。

编写一个有initializer_list意识的函数可以解决这个问题,但这会将一个完美转发的 emplace 变成一个复制和移动,这也不是很好。

编辑:(
上述链接代码,根据要求)

#include <cstdio>

template<typename T> struct container
{
    container() { puts("default"); }
    container(container const&) { puts("copy"); /* blah */ }
    template<typename... U> container(U&&... args) { puts("template");  /* new T[sizeof...(args)]{std::forward<T>(args)...};  blah blah */ }
};

int main()
{
    container<int> f;
    container<int> g{1,2,3};
    container<int> h(f); // <--- copy constructor most viable form?!
    return 0;
}
4

0 回答 0