4

我有一个变体类,它使用一些函数模板专业化来获取和设置不同的类型,这些类型在 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;
    }
}

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

4

1 回答 1

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);
   }
}
于 2012-05-03T20:19:43.727 回答