C++ *nix上的模板方法专门化

C++ *nix上的模板方法专门化,c++,linux,templates,gcc,C++,Linux,Templates,Gcc,我有一个variant类,它使用一些函数模板专门化来获取和设置不同的类型,这些类型在VisualStudio2010中编译并运行良好。然而,这段代码位于一个公共解决方案中,该解决方案也需要在redhat、ubuntu等平台上编译 我在非命名空间范围内收到了一个关于显式专门化的错误。我认为简单的解决方法是在类之外定义我的专门化,并在同一名称空间中使用类的范围限定符 然而,现在我得到的错误是,由于用于从各种类型转换的类的其他方法正在类中使用此模板,所以在实例化之后会发生专门化 那么,这样做的正确方法

我有一个variant类,它使用一些函数模板专门化来获取和设置不同的类型,这些类型在VisualStudio2010中编译并运行良好。然而,这段代码位于一个公共解决方案中,该解决方案也需要在redhat、ubuntu等平台上编译

我在非命名空间范围内收到了一个关于显式专门化的错误。我认为简单的解决方法是在类之外定义我的专门化,并在同一名称空间中使用类的范围限定符

然而,现在我得到的错误是,由于用于从各种类型转换的类的其他方法正在类中使用此模板,所以在实例化之后会发生专门化

那么,这样做的正确方法是什么:

namespace Example
{
    class CSomeVariant
    {
    public:
        bool toString(std::string& out)
        {
            return get(out);
        }
    private:
        template <typename T>
        bool get(T& val)
        {
            try {
                val = boost::any_cast<T>(m_stored);
            }
            catch (...) {
                return false;
            }
            return true;
        }

        boost::any m_stored;
    };

    template<>
    bool CSomeVariant::get(std::string& val)
    {
        try {
            if (m_stored.type() != typeid(std::string))
               val = convertToString();
            else
               val = boost::any_cast<std::string>(m_stored);
        }
        catch(...) {
            return false;
        }
        return true;
    }
}
名称空间示例
{
类CSomeVariant
{
公众:
bool-toString(标准::字符串和输出)
{
退换货;
}
私人:
模板
布尔盖特(T&val)
{
试一试{
val=boost::任意_转换(存储的m_);
}
捕获(…){
返回false;
}
返回true;
}
boost::存储的任何m_;
};
模板
boolcsomevariant::get(std::string&val)
{
试一试{
if(m_存储的.type()!=typeid(std::string))
val=convertToString();
其他的
val=boost::任意_转换(存储的m_);
}
捕获(…){
返回false;
}
返回true;
}
}

注意:这不是实际的代码,但我相信它表明了问题所在。

问题在于您在类定义中使用了
get()
函数,然后对其进行了专门化,这是不允许的。从14.7.3第6段

如果模板、成员模板或类模板的成员 明确专业化,则应声明该专业化 在第一次使用会导致 在中的每个翻译单元中进行隐式实例化 发生这种使用的原因;无需诊断。如果程序 不提供显式专门化和 或者专门化的使用方式会导致 发生隐式实例化,或者该成员是虚拟成员 功能,程序格式错误,无需诊断

一种解决方案是对类定义重新排序,以便在任何使用之前声明专门化。在本例中,我能够将函数的内联使用移动到专门化之后

#include <string>
#include <boost/any.hpp>
namespace Example
{
    class CSomeVariant
    {
    public:
        bool toString(std::string& out);

    private:
       template <typename T>
       bool get(T& val)
       {
           try {
              val = boost::any_cast<T>(m_stored);
           }
           catch (...) {
               return false;
           }
           return true;
       }

       boost::any m_stored;
   };

   template<>
   bool CSomeVariant::get(std::string& val)
   {
       try {
           if (m_stored.type() != typeid(std::string))
              val = convertToString();
           else
              val = boost::any_cast<std::string>(m_stored);
       }
       catch(...) {
           return false;
       }
       return true;
   }


   inline bool CSomeVariant::toString(std::string& out)
   {
        return get(out);
   }
}
#包括
#包括
名称空间示例
{
类CSomeVariant
{
公众:
bool-toString(std::string&out);
私人:
模板
布尔盖特(T&val)
{
试一试{
val=boost::任意_转换(存储的m_);
}
捕获(…){
返回false;
}
返回true;
}
boost::存储的任何m_;
};
模板
boolcsomevariant::get(std::string&val)
{
试一试{
if(m_存储的.type()!=typeid(std::string))
val=convertToString();
其他的
val=boost::任意_转换(存储的m_);
}
捕获(…){
返回false;
}
返回true;
}
内联boolcsomevariant::toString(std::string&out)
{
退换货;
}
}

奇怪,看起来应该行得通……你为什么用专业化而不是?@ildjarn嗯,因为。。。说得好。哇,我现在觉得自己很笨。你比我快了1分钟!我刚刚在我刚到的高级C++元编程副本中读到过这篇文章。这篇文章有很多内容,但这是可行的。我同意ildjarn的建议,因为我喜欢完全取消专门化。@AJG85作为一般规则,我尽量避免专门化函数,并尽可能使用重载。规则更容易遵守。