Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 获取模板类对象的地址将导致模板参数的完全实例化_C++_Templates_Gcc_Instantiation - Fatal编程技术网

C++ 获取模板类对象的地址将导致模板参数的完全实例化

C++ 获取模板类对象的地址将导致模板参数的完全实例化,c++,templates,gcc,instantiation,C++,Templates,Gcc,Instantiation,我用g++4.6和4.8编译这段代码时出错。 g++4.2和4.4可以。这是一个bug还是一些新的语言特性 template <typename T> struct A { typedef typename T::value_type type; }; template <typename U> struct B { void bar () { } void foo () { // OK this->bar (); // OK

我用g++4.6和4.8编译这段代码时出错。 g++4.2和4.4可以。这是一个bug还是一些新的语言特性

template <typename T>
struct A { typedef typename T::value_type type; };

template <typename U>
struct B
{
  void bar () { }
  void foo ()
  {
    // OK
    this->bar ();

    // OK
    (*this).bar ();

    // Error in g++ 4.6-4.8 
    // leads to full instantiating of template arg "U"
    (&*this)->bar ();
  }
};

int main ()
{
  B< A<void> > b;
  b.foo ();
  return 0;
}
我发现这些错误和解决方法完全不合逻辑。

分析/解释: 您看到的是浅实例化,而不是完整实例化(请参见下面的证据)

ADL是罪魁祸首

假设II我怀疑这里有一个与ADL相关的东西(类可以具有内联声明的静态自由函数(friends)。也许编译器需要实例化整个类模板,以确保它看到其中声明的运算符重载(以便进行重载解析)

标准在这里支持我:§3.4.2(n3337中的第46页):

²[snip]名称空间和类的集合完全由 函数参数的类型(以及任何模板的名称空间 模板参数)。[snip]名称空间和类的集合是 按以下方式确定:

  • [剪报]

  • 如果T是类类型(包括联合),则其关联的类为: 类本身;它所属的类(如有);及其直接和间接的 间接基类。其关联的命名空间是 它的关联类是成员。此外,如果T是类模板 专门化,其关联的名称空间和类还包括: 与模板类型关联的名称空间和类 为模板类型参数(不包括模板)提供的参数 模板参数);包含任何模板参数的名称空间 是成员;以及任何成员模板用作模板的类 模板参数是成员

粗体短语包括
class A
作为ADL的查找命名空间

解决方法: 在您的情况下,可以使用
std::addressof(b)
来代替
&b
,它会起作用

演示: 看

注:
(不合格id)
技巧在本标准§3.4.2中定义)

此外,您还可以验证模板参数(
A
)是否仅被实例化将格式不正确的typedef移动到成员函数中可以解决以下问题:

template <typename T> struct A {
    void uninstantiated() {
        typedef typename T::value_type type;
    }
    friend void freefunction(B<A>&) { std::cout << "ADL was here!\n"; }
};

历史:

  • 我注意到
    操作符&
    是问题所在,但
    std::addressof()
    还行
  • 我注意到使用任何(重载)操作符似乎都会触发这种行为

  • 这让我想到了我的“假设II”(见上文)

    我发现令人惊讶的是,它实际上是编译的,而你却没有编译。我本以为通过实例化模板(声明
    B
    ),你需要
    A
    才有意义。我的问题是:为什么这个->条()有效,(*this).bar()有效,(&*this)->条()会出错?在我看来,模板参数U[=A]在B类中的任何地方都没有使用,因此根本不应该实例化它(惰性模板实例化)。然而,当一个人得到B对象的地址时,情况就不是这样了。这里看起来像是g++编译器的bug,不是吗?我还不知道为什么会发生这种情况,但gcc、clang和EDG的最新版本在行为上都是一致的,也就是说,我怀疑标准强制要求它。@NikkiChumakov你在其中看到我的更新了吗?我很想知道你是否解决了这个问题,证明这是ADL,使用增加的相关标准引用。我想这应该可以。(我会整理一下格式)好的,我明白了。感谢您对标准条款的引用和解释。@NikkiChumakov I补充了更准确的说明,这是一个没有完全实例化的例子,以及如何证明这一点。我缩小了示例,还显示了
    A
    实际上是如何被用作
    freefunction(A)
    freefunction
    的查找命名空间的:<代码>ADL在这里@sehe很遗憾,我无法使用建议的解决方法。我不得不改用CRTP。它是有效的,但我并不真正理解它是如何工作的以及为什么工作的(-:请参阅我问题中的更新2。
    #include <tr1/functional>
    template <typename T>
    struct A { typedef typename T::value_type type; };
    
    template <typename Derived, typename U>
    struct B
    {
      Derived* derived (void) { return static_cast<Derived*>(this); }
    
      void bar () { }
      void foo ()
      {
        // error with recent compiler.
        // std::tr1::bind (&B::bar, this) ();
    
        // now ok
        std::tr1::bind (&Derived::bar, derived ()) ();
      }
    };
    
    struct C: B<C, A<void> >
    {
    };
    
    int main ()
    {
      C c;
      c.foo ();
      return 0;
    }
    
    #include <vector>
    #include <iostream>
    
    struct Base {};
    
    template <typename U> struct B : Base { };
    
    template <typename T> struct A {
        typedef typename T::value_type type;
        friend void freefunction(B<A>&) { std::cout << "ADL was here!\n"; }
    };
    
    void freefunction(Base& /*acceptAll*/) {}
    
    int main ()
    {
        B< A<std::vector<int> > >  a;
        B< A<void> >               b;
    
        // surrounding with parens prevents ADL:
        (freefunction)(a);
        (freefunction)(b); // selects ::freefunction(Base&)
    
        freefunction(a);   // ADL selects friend inline freefunction(B< A<std::vector<int> > >&)
      //freefunction(b);   // ADL fails: template arg cannot be (shallow) instantiated
    }
    
    ADL was here!
    
    template <typename T> struct A {
        void uninstantiated() {
            typedef typename T::value_type type;
        }
        friend void freefunction(B<A>&) { std::cout << "ADL was here!\n"; }
    };
    
    ADL was here!
    ADL was here!