我最近遇到了一个新警告:
继承构造函数不会继承省略号
我正在尝试管道
Object{42}; // ... into an init that handles integers
...和...
Object{3.14}; // ... into an init that handles FLOATS
......使用一些SFINAE狡猾:
#define DECAY(T) typename std::decay<T>::type
#define IS_INTEGRAL(T) std::is_integral< DECAY(T) >::value
#define IS_FLOATING(T) std::is_floating_point< DECAY(T) >::value
#define SUBFAIL_UNLESS(PRED) typename X = \
typename std::enable_if<PRED>::type
// long, float
template<typename T, SUBFAIL_UNLESS(IS_INTEGRAL(T)) >
explicit Object( T&& t ) : Object{ pyob_from_integral(t) } { }
template<typename T, SUBFAIL_UNLESS(IS_FLOATING(T)) >
explicit Object( T&& t, ... ) : Object{ pyob_from_floating(t) } { }
private:
template<typename T> PyObject* pyob_from_integral( T t ) {
cout << "integral"; return nullptr;
}
template<typename T> PyObject* pyob_from_floating(T t) {
cout << "FLOATING"; return nullptr;
}
。在coliru可以看到演示警告的完整代码。
现在...的目的是避免编译器抛出错误,因为它认为我有两个单独的模板模板化构造函数。即知道它们是不相交的/相互排斥的是不够聪明。
此警告的重要性是什么,以及如何围绕它进行编码?
PS请注意,有充分的理由不仅仅提供一些构造函数重载;我故意简化方案,使问题尽可能清楚。
编辑:工作简化的测试用例证明了...... here的必要性。 (即如果你删除它,它就不再编译了。)
答案 0 :(得分:5)
根据我的理解,OP试图通过引入省略号...
来解决的问题是,您可能无法定义具有相同签名的两个函数(违反ODR)。
签名的概念扩展到功能模板。但是,函数模板的签名包括其模板参数。根据最近的github草案,基于N4296:
[defns.signature.templ]
签名
&lt;功能模板&gt; name,参数类型列表(8.3.5),封闭命名空间(如果有), 返回类型和模板参数列表
[basic.link] /9.4和[temp.over.link]指定在什么情况下两个函数模板是等效的。在OP的情况下,您可以通过稍微改变SFINAE的应用方式来使这些功能模板的签名不同:
template<typename T,
typename std::enable_if< std::is_integral<T>::value, int >::type = 0>
explicit Object(T&&);
template<typename T,
typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
explicit Object(T&&);
第二个(非类型)模板参数的类型是依赖于第一个模板参数的表达式。这些表达区分了两个模板;有关详细信息,请参阅[temp.over.link] / 5。在OP中,第二个模板参数只是一种类型。因此,这两个模板的模板参数是等效的,默认模板参数只有一个区别,它不是签名的一部分。
当使用构造函数继承时,省略号的问题在于继承的构造函数会发出省略号。这是构造函数继承的一个怪癖,如[class.inhctor] /1.4中所指定的那样,当继承OP中的两个ctors时,这会导致候选继承构造函数集中的两个函数模板签名。我不明白标准如何解决这个问题; clang ++和g ++同意它是非法的,ctor&#34;不能继承&#34;或者&#34;不能超载&#34;。
答案 1 :(得分:1)
当基类有省略号运算符时,它在被继承的运算符中被忽略(当使用...继承时):
class A {
public:
A(int,...);
};
class B: public A {
public:
using A::A;
};
在这个例子中,B类有一个B :: B(int),它将调用A :: A(int,...),其中......等于什么,因为它没有默认参数值,但是缺省值是构造函数继承的唯一且必需的选项,请参阅标准的12.9.1:
&#34;对于X的每个非模板构造函数,它至少有一个带有默认参数的参数,构造函数集是通过省略任何省略号参数规范并连续省略带有默认参数的参数而得到的参数类型列表的结尾,以及&#34; ... &#34;对于X的每个构造函数模板,它至少有一个带有默认参数的参数,构造函数模板集这是因为省略了任何省略号参数规范,并且在参数类型列表的末尾使用默认参数连续省略了参数。&#34;
我认为你不能继承一个带有...的构造函数,在这种情况下你不能重新定义它,因为它不会与继承的那个冲突。