简体   繁体   English

专门化模板成员功能

[英]Specializing template member function

I'm trying to specify a function of a template class, that should only work when an object of the class is created using specific types (KEY as std::string and VALUE as std::string ). 我正在尝试指定模板类的功能,该功能仅在使用特定类型(KEY作为std::string和VALUE作为std::string )创建该类的对象时才起作用。

My template ( Dictionary.h ), simplified: 我的模板( 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

The implode function is the one I'm trying to implement. implode函数是我要实现的函数。 Trying to compile the above results in this: 尝试编译以上结果:

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

I'm not sure how I should implement this. 我不确定该如何实施。 Any hints? 有什么提示吗?


EDIT: 编辑:

I've encountered some new problems while trying out @TartanLlama's answer. 我在尝试@TartanLlama的答案时遇到了一些新问题。

My current code is as follows (irrelevant parts left out): Dictionary.h : 我当前的代码如下(忽略了不相关的部分): 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

You can specialize by explicitly instantiate your method member like this outside your class definition : 您可以通过在类定义之外显式实例化方法成员来进行专门化:

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;
}

Live Code 现场代码

Note that I have fixed other errors (no need to add typename in return method type, use const_iterator...) 请注意,我已经修复了其他错误(无需在返回方法类型中添加typename,请使用const_iterator ...)

You are attempting to explicitly-specialize implode , but it's not a template. 您正在尝试显式专业化implode ,但这不是模板。

You could use SFINAE to only enable the function if KEY and VALUE are std::string : 如果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 {
    //...
}

You could use static_assert to issue an error if the function is instantiated for the wrong Dictionary specialization: 如果为错误的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");
    //...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM