Mor*_*enn 13 c++ boost language-lawyer c++11 inheriting-constructors
我试图创建一个派生自的类,boost::multiprecision::mpz_int并让它继承基类构造函数:
#include <boost/multiprecision/gmp.hpp>
using namespace boost::multiprecision;
struct Integer:
mpz_int
{
using mpz_int::mpz_int;
};
Run Code Online (Sandbox Code Playgroud)
g ++ 4.9.0给出了以下错误:
main.cpp:8:20: error: 'template<class tag, class Arg1, class Arg2, class Arg3, class Arg4> Integer::Integer(const boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>&)' inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
using mpz_int::mpz_int;
^
main.cpp:8:20: error: conflicts with version inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: 'template<class Other, boost::multiprecision::expression_template_option ET> Integer::Integer(const boost::multiprecision::number<Backend, ExpressionTemplates>&)' inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: conflicts with version inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: 'template<class Other, boost::multiprecision::expression_template_option ET> Integer::Integer(const boost::multiprecision::number<Backend, ExpressionTemplates>&)' inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: conflicts with version inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: 'template<class V> Integer::Integer(const V&)' inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: conflicts with version inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: 'template<class V> constexpr Integer::Integer(const V&)' inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: conflicts with version inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: 'template<class V> Integer::Integer(const V&)' inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
main.cpp:8:20: error: conflicts with version inherited from 'boost::multiprecision::number<boost::multiprecision::backends::gmp_int>'
Run Code Online (Sandbox Code Playgroud)
事实是,我不知道为什么会这样.以下解决方法实现了我想要做的事情:
struct Integer:
mpz_int
{
template<typename... Args>
Integer(Args&&... args):
mpz_int(std::forward<Args>(args)...)
{}
};
Run Code Online (Sandbox Code Playgroud)
任何人都能解释为什么第一个例子会产生错误吗?我认为继承基类构造函数并将值转发给它们大致相同.我想我错了,但我仍然有兴趣了解其中的差异.
编辑:我会说清楚.我不在乎在所有是否有更好的方法来做到这一点(有吨).我问的唯一问题是为什么构造函数继承在这种情况下失败了.是由于编译器错误还是标准中某处的某些模糊规则?
这似乎是由构造函数的默认参数mpz_int(mpz_int是特定实例化的typedef boost::multiprecision::number)引起的,它们用于SFINAE(例如,给定一个template <class V>构造const V &函数,如果V满足条件X ,则选择一个构造函数,如果满足条件X ,则选择另一个构造函数)V满足标准Y).
一个小的repro是:
#include <type_traits>
struct foo {
template<class T>
foo(T , typename std::enable_if<std::is_integral<T>::value>::type * = nullptr) { }
template<class T>
foo(T , typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr) { }
};
struct bar : foo {
using foo::foo;
};
int main() { }
Run Code Online (Sandbox Code Playgroud)
这在clang而不是g ++中编译,产生相同的错误.(值得注意的是,虽然clang编译上面的repro代码,但如果你试图使用带有单个参数的继承构造函数,它实际上不起作用,这几乎同样糟糕.你可以使它在clang中工作,但是,显式提供第二个参数.)
我们甚至可以通过简单地使用来跳过foo构造函数的模板性:
struct foo {
foo(double, int = 0) { }
foo(double, double = 0) { }
};
Run Code Online (Sandbox Code Playgroud)
并且仍然得到相同的结果 - g ++中的错误,clang中的确定.
现在,问题是这个结构是否应该按照标准接受.不幸的是,没有明确的答案.§12.9[class.inhctor]/p1说
命名构造函数的using声明(7.3.3)隐式声明了一组继承构造函数.来自using-declaration中指定 的类的候选继承构造函数集由实际构造函数和由默认参数转换产生的名义构造函数组成,如下所示:
X
- 所有非模板构造函数
X,和- 对于每个非模板构造函数
X至少有一个带有默认参数的参数,构造函数集是通过省略任何省略号参数规范并从参数类型列表的末尾连续省略带有默认参数的参数而得到的,以及- 所有构造函数模板
X,和- 对于每个构造函数模板,
X其至少有一个带有默认参数的参数,构造函数模板集合,省略任何省略号参数规范,并从参数类型列表的末尾连续省略带有默认参数的 参数.
问题是标准实际上没有指定如果这个连续省略参数和默认参数过程导致两个具有相同签名的构造函数会发生什么.(注意,使用foo上面的两个模板构造函数,省略带有default参数的参数会给出签名template<class T> foo(T);.)虽然第7段有一个注释说明
如果两个using声明声明继承具有相同签名的构造函数,则程序格式错误(9.2,13.1),因为第一个using声明引入的隐式声明的构造函数 不是用户声明的构造函数,因此不排除后续using声明具有相同签名的构造函数的另一个声明.
这里我们只有一个使用声明,因此该注释不适用,并且,虽然确实禁止重复声明,但可以说第1段中对集合的引用意味着重复的签名将被简单地视为一个,所以单个using声明不会引入重复声明.
事实上,这个问题是针对该标准的两个缺陷报告的主题:CWG 1645和CWG 1941,并且不清楚这些缺陷报告将如何解决.在CWG第1645期的2013年注释中指出的一种可能性是删除这些继承的构造函数(来自多个基础构造函数),因此它们仅在使用时才会导致错误.CWG问题1941中提出的另一种方法是使继承构造函数的行为与引入到派生类中的其他基类函数一样.
| 归档时间: |
|
| 查看次数: |
511 次 |
| 最近记录: |