Templates 隐式转换运算符隐藏规则

Templates 隐式转换运算符隐藏规则,templates,gcc,c++11,Templates,Gcc,C++11,介绍我的问题的唯一方法是首先提供一个示例: template<typename T> class foo { public: foo() {} foo(const foo&) {} }; template<template<typename> class C> class convertible_to { public: template<type

介绍我的问题的唯一方法是首先提供一个示例:

template<typename T>
class foo
{
    public:
        foo()
        {}

        foo(const foo&)
        {}
};

template<template<typename> class C>
class convertible_to
{
    public:
        template<typename T>
        operator C<T> ();
};

class convertible_to_foo : public convertible_to<foo>
{
        public:
        template<typename T>
        operator foo<T>()
        {
            return foo<T>();
        }
};
并抱怨从
convertible\u到\u foo
foo
的转换不明确。 这是预期行为还是GCC可能出错?

谢谢你阅读这个问题

编辑

为了理解我为什么要使用这种看起来很奇怪的技术,请参考我下面针对karrek的评论,并查看下面的用例:

考虑以下类别:

template<typename TYPE>
class real;

template<typename TYPE>
class complex;
模板
类真实;
模板
阶级情结;
我的设计是为了最大限度地减少由于值条件作用而产生的异常,即域错误。例如,将函数sqrt应用于类real的对象将始终返回complex类型的对象,而不是允许错误发生

到目前为止还不错,但现在最好有一些预定义的常数,比如pi或复数i。最简单的方法显然是如下声明:

real<double> pi = 3.14...;
real pi=3.14。。。;
但是,作为一个完美主义程序员(可能也是),我意识到这种方法有两个问题:

1-例如,需要高精度pi的应用程序不会从使用real

2-关注内存使用的应用程序将无法使用此pi,因为使用real类型的对象操作它将生成real类型的对象。(好吧,每次操作发生时显式地强制转换为实时转换是我想要避免的一件丑事)

我所看到的解决这个问题的最聪明的方法是设计常数,这些常数通过隐式转换运算符惰性地正确地计算它们自己:

template<template<typename> class C>
class scalar_constant
{
    public:
        scalar_constant& operator = (const scalar_constant&) = delete;

        template<typename T>
        operator C<T> () const;
};

class pi_t : public scalar_constant<real>, public scalar_constant<complex>
{
    public:
        template<typename T>
        operator real<T> () const
        {
            return {std::acos(static_cast<T>(-1))};
        }

        template<typename T>
        operator complex<T> () const
        {
            return {std::acos(static_cast<T>(-1))};
        }
};

const pi_t pi = pi_t();
模板
类标量常数
{
公众:
标量常数&运算符=(常数标量常数&)=delete;
模板
运算符C()常量;
};
类pi_t:公共标量_常量,公共标量_常量
{
公众:
模板
运算符实()常数
{
返回{std::acos(static_cast(-1))};
}
模板
运算符复数()常量
{
返回{std::acos(static_cast(-1))};
}
};
常数pi_t pi=pi_t();
这里的“概念检查”是绝对重要的,因为我不会为我决定提供的每个常量重载每个操作符。通过这种方式,我可以简单地为操作符提供一个支持SFINAE的重载,这只是继承“概念”以提供新常量的问题


很明显,我可以删除基类上未定义的转换运算符,这样问题就可以解决了,但这样一来,它就失去了整个概念的概念,即通过使程序由于未定义的继承函数而可能无法链接,从而强制执行概念检查,以及使编程人员(懒惰的我)更容易操作几年后回到这段代码,并能够添加另一个符合概念的类,只需查看概念本身并了解应该提供什么。

回答问题的第一部分。在此代码中

template<template<typename> class C>
class convertible_to
{
    public:
        template<typename T>
        operator C<T> ();
};

class convertible_to_foo : public convertible_to<foo>
{
        public:
        template<typename T>
        operator foo<T>()
        {
            return foo<T>();
        }
};
模板
可转换为
{
公众:
模板
运算符C();
};
敞篷车类别:公共敞篷车
{
公众:
模板
操作员foo()
        {
返回foo();
        }
};
如果继承自
convertible\u to
,我们不能期望
运算符C
应该隐藏,但如果继承自
convertible\u to
,则可以看到

<>这会使C++和模板比现在更复杂。所以没有这样的规则

我希望在convertible_to_foo中声明的隐式转换运算符to foo将隐藏,即重载

这混淆了术语。隐藏意味着在查看派生类时,只能看到派生类的转换函数,而不能看到基类。重载意味着您将看到这两个函数。如果派生函数与基函数同名,则派生函数中的函数将隐藏基函数中的函数

转换函数名的规则是:如果它们转换为同一类型,则其中两个名称相同。因此,如果在基类中有
运算符int
,在派生类中也有,那么派生函数将隐藏基类的函数。如果派生的表达式是
操作符float
,那么就没有隐藏。也没有重载,但如果在派生类中查找转换函数
运算符int
,则会找到基类,因为它不会被具有相同名称的派生函数隐藏

对于模板,其工作原理相同

struct A {
  template<typename T, typename U = int>
  operator T();
};

struct B : A {
  template<typename T = int, typename U>
  operator U();
};

派生类中的转换函数转换为完全相同的类型,因此我认为GCC不应该在这里产生歧义

对于
foo
,为什么要派生而不是将
convertible\u部分专门化为
to
?@kerrek的想法是通过使用c++0x std lib提供的元函数is\u base\u来实现某种概念检查,这样,如果我想启用/禁用一个需要转换为任何类型的模板函数/类,我可以通过检查convertible_to是否是类型的基来使用SFINAE。如果类型确实是从convertible_to派生的,但不要重载转换运算符,那么代码将进行编译,但显然不会链接,这使它成为一种非常有效的概念检查技术。您是否可以发布一个预期的用例示例?
std::is_convertible
有什么用处吗?那么,std::is_convertible将允许更多的类型符合我所期望的概念,那么我希望。应在几分钟内为问题添加一个具体的用例;)虽然我混淆了隐藏和重载这两个术语,但这是p
struct A {
  template<typename T, typename U = int>
  operator T();
};

struct B : A {
  template<typename T = int, typename U>
  operator U();
};
template<typename T>
operator foo<T> (); // after substituting "foo" for "C"