专门化模板成员函数

Specializing template member function

本文关键字:函数 成员 专门化      更新时间:2023-10-16

我正在尝试指定一个模板类的函数,该函数只有在使用特定类型(KEY作为std::string,VALUE作为std::string)创建该类的对象时才有效。

我的模板(Dictionary.h),简化:

#ifndef QB_DICTIONARY_H
#define QB_DICTIONARY_H
#include <map>
#include <string>
namespace QB {
    template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>>
    class Dictionary {
    public:
        typedef typename std::map<KEY, VALUE, COMPARE>::iterator iterator;
        typedef typename std::map<KEY, VALUE, COMPARE>::const_iterator const_iterator;
        Dictionary() {
        }
        Dictionary(const std::map<KEY, VALUE, COMPARE> & value) {
            this->value = value;
        }
        typename iterator begin() {
            return value.begin();
        }
        typename const_iterator begin() const {
            return value.cbegin();
        }
        typename iterator end() {
            return value.end();
        }
        typename const_iterator end() const {
            return value.cend();
        }
        // Trying to have the function work only when the template KEY and VALUE are of type std::string
        const std::string implode<std::string, std::string>(const std::string & valueSeparator, const std::string & pairSeparator) const {
            std::string result;
            for (iterator i = begin(); i != end(); i++) {
                if (i != begin()) {
                    result += pairSeparator;
                }
                result += iterator->first;
                result += valueSeparator;
                result += iterator->second;
            }
            return result;
        }
    private:
        std::map<KEY, VALUE, COMPARE> value;
    };
}
#endif

内爆函数是我正在尝试实现的函数。尝试在以下位置编译上述结果:

1>d:cloud storageonedriveprojectsqbqbdictionary.h(115): error C2143: syntax error: missing ';' before '<'
1>  d:cloud storageonedriveprojectsqbqbdictionary.h(133): note: see reference to class template instantiation 'QB::Dictionary<KEY,VALUE,COMPARE>' being compiled
1>d:cloud storageonedriveprojectsqbqbdictionary.h(115): error C2334: unexpected token(s) preceding '{'; skipping apparent function body

我不确定该如何实现。有什么提示吗?


编辑:

我在尝试@TartanLlama的答案时遇到了一些新问题。

我当前的代码如下(省略了不相关的部分):Dictionary.h:

#ifndef QB_DICTIONARY_H
#define QB_DICTIONARY_H
#include <map>
#include <string>
#include <type_traits>
namespace QB {
    template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>>
    class Dictionary {
    public:
        // ...
        const std::string implode(const std::string &, const std::string &) const;
        // ...
    };
    template<typename K=KEY, typename V=VALUE, typename COMPARE = std::less<KEY>>
    std::enable_if_t<std::is_same<std::string, K>{} && std::is_same<std::string, V>{}, const std::string> Dictionary<K, V, COMPARE>::implode(const std::string & valueSeparator, const std::string & pairSeparator) const {
        // ...
    }
}
#endif

您正试图显式地专门化implode,但它不是一个模板。

如果KEYVALUEstd::string:,则只能使用SFINAE启用该功能

template <typename K=KEY, typename V=VALUE>
std::enable_if_t<std::is_same<std::string, K>{} &&
                 std::is_same<std::string, V>{}, 
                 const std::string>
implode(const std::string & valueSeparator, 
        const std::string & pairSeparator) const {
    //...
}

如果函数被实例化为错误的Dictionary专用化:,则可以使用static_assert来发出错误

implode(const std::string & valueSeparator, 
        const std::string & pairSeparator) const { 
    static_assert(std::is_same<std::string, K>{} &&
                  std::is_same<std::string, V>{},
                  "KEY and VALUE must be std::string");
    //...
}

您可以通过在类定义之外显式实例化方法成员来进行专门化:

template<> std::string QB::Dictionary<std::string, std::string>::implode(const std::string & valueSeparator, const std::string & pairSeparator) const {
    std::string result;
    for (const_iterator i = begin(); i != end(); i++) {
        if (i != begin()) {
            result += pairSeparator;
        }
        result += i->first;
        result += valueSeparator;
        result += i->second;
    }
    return result;
}

实时代码

注意,我已经修复了其他错误(无需在返回方法类型中添加typename,使用const_iterator…)