代码之家  ›  专栏  ›  技术社区  ›  Fire Lancer

类模板专业设置有问题

  •  0
  • Fire Lancer  · 技术社区  · 15 年前

    我正在尝试将一些代码从VC9移植到G++中,但是我遇到了一个问题,模板专业显然不允许类成员使用。

    下面的代码是这些类方法的getValue特殊化错误的示例。在所有情况下,错误都是“错误:非命名空间范围内的显式专用化” class ...

    template<typename T> T getValue(const_iterator key)const
    {
        try{return boost::lexical_cast<T>(key->second);}
        catch(boost::bad_lexical_cast &e)
        {
            throw TypeParseError<T>(name, key->first, e.what());
        }
    }
    template<typename T> T getValue(const std::string &key)const
    {
        iterator i = find(key);
        if(i == end())throw KeyNotFound(name,key);
        else return getValue(i);
    }
    template<> std::string getValue<std::string>(const_iterator key)const
    {
        return key->second;
    }
    template<> std::string getValue<std::string>(const std::string &key)const
    {
        const_iterator i = find(key);
        if(i == end())throw KeyNotFound(name,key);
        else return i->second;
    }
    

    它只是不支持确切的语法,一个微小的更改会使它工作,还是我需要更改代码以避免这样的特殊化?如果是后者,一般来说哪种方法是最好的?

    2 回复  |  直到 15 年前
        1
  •  7
  •   Johannes Schaub - litb    15 年前

    您还没有显示包含这些函数声明的类定义。但我假设在某个类中声明这些模板。您必须定义外部的专门化:

    struct SomeClass {
       template<typename T> T getValue(const_iterator key)const
        {
            try{return boost::lexical_cast<T>(key->second);}
            catch(boost::bad_lexical_cast &e)
            {
                throw TypeParseError<T>(name, key->first, e.what());
            }
        }
        template<typename T> T getValue(const std::string &key)const
        {
            iterator i = find(key);
            if(i == end())throw KeyNotFound(name,key);
            else return getValue(i);
        }
    };
    
    template<> inline std::string SomeClass::getValue<std::string>(const_iterator key)const {
        return key->second;
    }
    
    template<> inline std::string SomeClass::getValue<std::string>(const std::string &key)const {
        const_iterator i = find(key);
        if(i == end())throw KeyNotFound(name,key);
        else return i->second;
    }
    

    记住,由于您在外部定义了它们,所以它们不是隐式内联的,因此您要么显式地将它们内联,要么将它们移动到 cpp 文件(不是头文件),然后像这样向前声明头文件中的专门化:

    template<> inline std::string SomeClass::getValue<std::string>(const_iterator key)const;
    template<> inline std::string SomeClass::getValue<std::string>(const std::string &key)const;
    

    如果省略了forward声明,编译器就无法知道是实例化函数还是使用显式专用化。远期申报说明了这一点。

        2
  •  3
  •   Gregory Pakosz    15 年前

    MSVC允许在类范围内显式专用化,而标准不允许。

    据我所见,您提供的代码来自类定义。在类的范围之外专门化。

    template<> inline std::string Foo::getValue<std::string>(const_iterator key)const {
        return key->second;
    }
    
    template<> inline std::string Foo::getValue<std::string>(const std::string &key)const {
        const_iterator i = find(key);
        if(i == end())throw KeyNotFound(name,key);
        else return i->second;
    }
    

    见:

    147.3.2

    应在 模板是哪个成员,或者,对于成员模板,在 封闭类或封闭类模板所在的命名空间 成员。成员函数、成员的显式专门化 类模板的类或静态数据成员应在 类模板所属的命名空间。