* nix上的模板方法专业化

时间:2012-05-03 20:10:50

标签: c++ linux templates gcc

我有一个变体类,它使用一些函数模板专门化来获取和设置使用Visual Studio 2010编译和工作的不同类型。但是这个代码位于一个通用的解决方案,它还需要在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;
    }
}

注意:这不是实际的代码,但我相信它会显示问题。

1 个答案:

答案 0 :(得分:3)

问题是您在类定义中使用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);
   }
}