Nik*_*kov 9 c++ gcc templates 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
(*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;
}
Run Code Online (Sandbox Code Playgroud)
g ++ inst.cc
inst.cc: In instantiation of ‘struct A<void>’:
inst.cc:20:5: required from ‘void B<U>::foo() [with U = A<void>]’
inst.cc:27:10: required from here
inst.cc:3:34: error: ‘void’ is not a class, struct, or union type
typedef typename T::value_type type;
^
Run Code Online (Sandbox Code Playgroud)
更新1:我知道A无法实例化.
问题是:为什么编译器试图在"(&*this) - > bar()"行中实例化它,而不是在"this-> bar()"或"(*this).bar()"行?
更新2:
建议的解决方法addressof (object)对我不起作用,因为实际上我在尝试使用时遇到了错误std::bind (&B::bar, this).真正的代码当然要复杂得多,bind并没有单独使用,但问题可以追溯到简单的std::bind表达式.
我不想重写或重新发明std::bind,所以我不得不使用CRTP使其工作:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我发现这些错误和变通办法完全不合逻辑.
seh*_*ehe 11
你所看到的是浅实例化,而不是满(见下面的证明).
ADL是这里的罪魁祸首.
假设II我怀疑这里有一个与ADL相关的东西(类可以有内联声明的静态自由函数(朋友).也许编译器需要实例化整个类模板,以确保它已经看到在其中声明的运算符重载(为了做重载决议).
标准支持我:§3.4.2(n3337中的p46):
² [snip]名称空间和类的集合完全由函数参数的类型(以及任何模板模板参数的名称空间)决定.[snip]命名空间和类的集合按以下方式确定:
[剪断]
如果T是类类型(包括联合),则其关联的类是:类本身; 它所属的成员,如果有的话; 及其直接和间接基类.其关联的名称空间是其关联类是成员的名称空间.此外,如果T是类模板特化,则其关联的名称空间和类还包括:与模板类型参数(模板模板参数除外)提供的模板参数类型相关联的名称空间和类 ; 任何模板模板参数都是成员的名称空间; 以及用作模板模板参数的任何成员模板的类都是成员.
粗体短语包括class A<void>作为ADL的查找命名空间.
在你的情况下std::addressof(b)可以使用而不是&b它将起作用.
见http://liveworkspace.org/code/4f85a06598eebe1d8060112be36f4a29
注意:该(unqualified-id)技巧在标准的§3.4.2中定义)
#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
}
Run Code Online (Sandbox Code Playgroud)
打印
ADL was here!
Run Code Online (Sandbox Code Playgroud)
此外,您可以验证模板argument(A<void>)仅实例化浅实例化.将格式错误的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"; }
};
Run Code Online (Sandbox Code Playgroud)
输出(http://liveworkspace.org/code/a15c933293281d0926e8b1ff39180079)
ADL was here!
ADL was here!
Run Code Online (Sandbox Code Playgroud)
历史:
operator&了问题,但std::addressof()还可以!这导致我的'假设II'(见上文)