GCC 7中模板类的模板成员函数的专业化

问题描述 投票:3回答:3

我无法使用GCC 7.3编译以下代码:

    template <class C>
    class BasicScalarFormatter
    {
    public:

        typedef std::basic_string<C> String;

        template<typename T>
        static String ToString(T val)
        {
            return String{};
        }

    };

    template<class C>
    typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
    {
        return String{};
    }

怎么了?

使用VC2017,如果在类中定义了ToString,它将编译:

    template <class C>
    class BasicScalarFormatter
    {
    public:

        typedef std::basic_string<C> String;

        template<typename T>
        static String ToString(T val)
        {
            return ToBasicString<C, T>(val);
        }

        template<>
        static String ToString(bool val)
        {
            return String{};
        }
    }

make it compile with GCC I moved ToString outside of the class,但它仍然没有编译。 GCC错误消息是:

ource_file.cpp:21:98: error: template-id ‘ToString<bool>’ in declaration of primary template
         typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
                                                                                                  ^
source_file.cpp:21:50: error: prototype for ‘BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString(bool)’ does not match any in class ‘BasicScalarFormatter<C>’
         typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
                                                  ^
source_file.cpp:14:27: error: candidate is: template<class C> template<class T> static BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString(T)
             static String ToString(T val)

看到它online here

c++ gcc
3个回答
3
投票

ToString是另一个模板类的模板成员。

首先,如果不专门设计外部模板,则无法专门构建内部模板。也就是说,你必须首先专门化一些BasicScalarFormatter的特定实例,然后采取它,然后才能专门化其成员模板方法的特定实例。但是,这种专业化当然只适用于专业化的BasicScalarFormatter

您的明显意图是不对外部模板进行特化,而是对外部模板类的所有实例的此类成员进行特化。

这里没有真正干净的解决方案,但这种通用设计模式通常很简单,智能编译器最终会优化掉额外的重定向:

#include <string>

template<typename C, typename T> class ToStringHelper {

public:

    static std::basic_string<C> helper()
    {
        return std::basic_string<C>();
    }
};

template<typename C> class ToStringHelper<C, bool> {

public:

    static std::basic_string<C> helper()
    {
        return std::basic_string<C>();
    }
};

template <class C>
class BasicScalarFormatter
{
public:

        typedef std::basic_string<C> String;

        template<typename T>
        static String ToString(T val)
        { 
            return ToStringHelper<C,T>::helper();
        }
};

void foo()
{
    BasicScalarFormatter<char> c;

    c.ToString(0);

    c.ToString(true);
}

所以,在这一点上,你最终得到了一个帮助类的静态方法。您的最终目标显然是使用原始模板的成员。好吧,你总是可以将this传递给这个helper(),并让它对它做一些事情,或者用它来调用一个调用类的方法。

然后,正如我所说的那样,希望你的编译器能够摆脱这种额外的间接层,可能会在这里和那里散布一些inline关键字来鼓励它,或者使用强力并使用你的编译器扩展来强制它内联一切。

用gcc 8测试。


0
投票

您在类模板中定义了函数模板时缺少一个template关键字。这应该工作:

template<class C>
template<>
typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
{
    return String{};
}

0
投票

当您使用模板参数template <typename C>实现类的方法时,您缺少C

试试这样:

#include <string>

template <class C>
class BasicScalarFormatter
{
public:

    typedef std::basic_string<C> String;

    template<typename T>
    static String ToString(T val);

};

template <typename C>
template <typename T>
typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::
ToString(T val)
{
    return String{};
}

哪个应该与GCC 7.3编译,请参阅here

© www.soinside.com 2019 - 2024. All rights reserved.