首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用boost::multiprecision::mpz_int的构造器继承失败

使用boost::multiprecision::mpz_int的构造器继承失败
EN

Stack Overflow用户
提问于 2014-07-23 13:49:01
回答 1查看 612关注 0票数 13

我试图创建一个从boost::multiprecision::mpz_int派生的类,并让它继承基类构造函数:

代码语言:javascript
复制
#include <boost/multiprecision/gmp.hpp>

using namespace boost::multiprecision;

struct Integer:
    mpz_int
{
    using mpz_int::mpz_int;
};

g++ 4.9.0给了我the following error

代码语言:javascript
复制
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>'

事实是我不知道为什么会发生这种事。以下解决方法实现了我想要做的事情:

代码语言:javascript
复制
struct Integer:
    mpz_int
{
    template<typename... Args>
    Integer(Args&&... args):
        mpz_int(std::forward<Args>(args)...)
    {}
};

有人能解释为什么第一个例子会产生错误吗?我认为继承基类构造函数并将值转发给它们做了大致相同的事情。我想我错了,但我还是想知道区别。

编辑:,我会说清楚的。我根本不在乎是否有更好的方法来实现这一点(有吨)。我问的唯一问题是为什么构造函数继承在这种情况下失败。这是由于编译器的错误还是标准中某个不明确的规则造成的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-04 04:02:35

这似乎是由's constructors引起的(mpz_intboost::multiprecision::number的一个特定实例化的类型),用于SFINAE (例如,给定一个接受const V &template <class V>构造函数,如果V满足标准X,选择一个构造函数,如果V满足标准Y,则选择另一个构造函数)。

一个小复制品是:

代码语言:javascript
复制
#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() { }

这个compiles in clang but not g++产生同样的错误。(值得注意的是,当clang编译上面的repro代码时,如果您尝试使用带有单个参数的继承构造函数,则it doesn't actually work几乎同样糟糕。不过,您可以通过explicitly supplying the second parameter使其在clang中工作。)

我们甚至可以简单地使用以下方法来实现's constructors

代码语言:javascript
复制
struct foo {
    foo(double, int = 0) { }
    foo(double, double = 0) { }
};

仍然得到相同的结果-- g++中的错误,clang中的好。

现在的问题是,这个结构是否真的应该按照标准被接受。不幸的是,没有明确的答案。§12.9 class.inhctor./p1指出

一个使用声明(7.3.3),它隐式地声明了一组继承构造函数。在using-声明中命名的类X中继承的构造函数的候选集合包括实际的构造函数和由默认参数转换产生的概念构造函数,如下所示:

  • X的所有非模板构造函数,以及
  • 对于至少有一个参数具有默认参数的X的每个非模板构造函数,由省略任何省略参数规范和从参数类型列表的末尾连续省略带有默认参数的参数而产生的构造函数集,以及
  • X的所有构造函数模板,以及
  • 对于至少有一个参数具有默认参数的X的每个构造函数模板,由省略任何省略参数规范和从参数类型列表的末尾连续省略带有默认参数的参数而产生的构造函数模板集。

问题是,如果这个过程导致两个具有相同签名的构造函数,那么标准实际上并没有指定会发生什么。(请注意,对于上述两个foo模板构造函数,省略带有默认参数的参数将给出签名template<class T> foo(T);)。而第7段有个注释说

如果两个使用-声明声明具有相同签名的继承构造函数,则程序的格式不正确(9.2,13.1),因为由第一个user声明引入的隐式声明构造函数不是用户声明的构造函数,因此不排除通过随后的使用-声明来声明具有相同签名的构造函数的另一个声明。

在这里,我们只有一种使用声明,因此说明不适用,虽然重复声明确实被禁止,但可以争辩的是,第1款中对一套声明的提及意味着重复签名将被简单地视为一项声明,因此单一使用-声明不会引入重复声明。

这个问题实际上是两个违反标准的缺陷报告的主题:CWG 1645CWG 1941,目前还不清楚如何解决这些缺陷报告。在CWG第1645期的2013年说明中指出,一种可能性是删除这种继承的构造函数(来自多个基本构造函数),这样它们只在使用时才会导致错误。1941年CWG问题中提出的另一种方法是使继承构造函数的行为与引入到派生类中的其他基类函数类似。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24912280

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档