C++ 非命名空间范围中的显式专门化 模板 类约束 { 公众: CConstraint() { } 虚拟~CConstraint() { } 模板 无效验证(int位置,int约束[]) { } 模板 无效验证(int,int[]) { } };

C++ 非命名空间范围中的显式专门化 模板 类约束 { 公众: CConstraint() { } 虚拟~CConstraint() { } 模板 无效验证(int位置,int约束[]) { } 模板 无效验证(int,int[]) { } };,c++,templates,gcc,C++,Templates,Gcc,在g++下编译此文件会出现以下错误: 非命名空间作用域“class CConstraint”中的显式专门化 在VC中,它编译得很好。有人能告诉我解决方法吗?在这种情况下,VC++是不兼容的-显式专门化必须在命名空间范围内。C++03,§14.7.3/2: 应在模板为成员的名称空间中声明显式专门化,或对于成员模板,在封闭类或封闭类模板为成员的名称空间中声明显式专门化。 类模板的成员函数、成员类或静态数据成员的显式专门化应在类模板所属的命名空间中声明 此外,由于C++03,§14.7.3/3,如果不

在g++下编译此文件会出现以下错误:

非命名空间作用域“class CConstraint”中的显式专门化


在VC中,它编译得很好。有人能告诉我解决方法吗?

在这种情况下,VC++是不兼容的-显式专门化必须在命名空间范围内。C++03,§14.7.3/2:

应在模板为成员的名称空间中声明显式专门化,或对于成员模板,在封闭类或封闭类模板为成员的名称空间中声明显式专门化。
类模板的成员函数、成员类或静态数据成员的显式专门化应在类模板所属的命名空间中声明

此外,由于C++03,§14.7.3/3,如果不显式地专门化包含类,则无法专门化成员函数,因此一种解决方案是让
Verify()
转发到一个可能专门化的自由函数:

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

    virtual ~CConstraint()
    {
    }

    template <typename TL>
    void Verify(int position, int constraints[])
    {       
    }

    template <>
    void Verify<int>(int, int[])
    {   
    }
};
名称空间详细信息{
模板无效验证(int,int[]){}
模板无效验证(int,int[]){}
}
模板类CConstraint{
// ...
模板无效验证(int位置,int约束[]){
细节::验证(位置、约束);
}
};

另一种解决方法是将其委托给私有函数并重载该函数。这样,您仍然可以访问
*This
的成员数据和外部模板参数类型

namespace detail {
    template <typename TL> void Verify     (int, int[]) {}
    template <>            void Verify<int>(int, int[]) {}
}

template<typename T> class CConstraint {
    // ...
    template <typename TL> void Verify(int position, int constraints[]) {
        detail::Verify<TL>(position, constraints);
    }
};
模板
结构标识{typedef T type;};
模板
类约束
{
公众:
模板
无效验证(int位置,int约束[])
{
验证(位置、约束、标识());
}
私人:
模板
无效验证(int,int[],标识)
{
}
无效验证(int,int[],标识)
{
}
};

您可能无法显式地专门化成员模板,但可以部分地专门化它。如果您添加第二个参数“int dummyParam”并将其添加到专门化中,那么它应该可以与两个编译器一起使用


并不是说我在10秒前就知道这一点,而是在谷歌上搜索同一个错误时,我遇到了一个错误,它对我的成员模板专门化起到了作用。

甚至更好:您可以将部分专门化与默认模板参数相结合。这种方式对VC++代码的修改很小,因为对专用函数的调用不需要修改

template<typename T>
struct identity { typedef T type; };

template<typename T>
class CConstraint
{
public:

  template <typename TL>
  void Verify(int position, int constraints[])
  {
    Verify(position, constraints, identity<TL>());
  }

private:
  template<typename TL>
  void Verify(int, int[], identity<TL>)
  {

  }

  void Verify(int, int[], identity<int>)
  {

  }
};
模板
无效验证(int位置,int约束[])
{
}
模板
无效验证(int,int[])
{
}

只需将模板专门化放在类声明之外即可。 gcc不允许内联模板专门化

作为另一个选项,只需删除行 模板
似乎对我有用。

在这种情况下不符合:一如既往:)?模板和VC++没有很好地结合:/从某种意义上说,它是不兼容的,它会让你做一些标准通常不允许的事情-这对于一开始就符合的代码来说不是问题(你写这样的代码,对吧?~)。真正的一致性问题是,它不会编译标准要求编译的东西,或者与指定的行为不同。例如,由于缺少两阶段查找而产生的微妙陷阱…:|为什么语言开发人员会对程序员开发人员这样做?他们是否在想,
我们如何使这种语言更难读写?
这个答案不再正确,在符合C++14(&更高版本)的编译器中,现在允许在类范围内进行专门化:非常感谢。我也在寻找这个,因为我需要访问它。希望我能选择两个答案。如果我是你,我会选择这个答案@约翰内斯:你的答案非常完美,谢谢。谢谢你,谢谢你,谢谢你,谢谢你,约翰内斯·朔布,谢谢你的回答。这个答案比公认的答案有用得多。自从C++11出现以来,有什么变化吗?C++03中不允许使用默认模板参数,只有C++0x/11。对不起,我错了:你不能部分地专门化一个函数。@Xeo:我猜你的意思是不允许在C++03中使用函数?默认模板参数是在模板参数中
=
之后指定的模板参数(14.3)。可以为任何类型的模板参数(类型、非类型、模板)指定默认模板参数。默认模板参数可以在类模板声明或类模板定义中指定。默认模板参数不得在函数模板声明或函数模板定义中指定,也不得在类模板成员定义的模板参数列表中指定。“不能部分地专门化函数注意,这在C++17中不再是一个问题。请看第一句关于金钱的话:“gcc不允许内联模板专门化”。删除
模板对我来说也很有效。
template <typename TL, class Dummy=int>
void Verify(int position, int constraints[])
{
}

template <class Dummy=int>
void Verify<int, Dummy>(int, int[])
{
}