如何对复杂的模板化函数进行显式实例化?和相关的 Intellisense 错误

Posted

技术标签:

【中文标题】如何对复杂的模板化函数进行显式实例化?和相关的 Intellisense 错误【英文标题】:How do I do an explicit instantiation of a complex templated function? and related Intellisense error 【发布时间】:2020-06-11 19:23:35 【问题描述】:

更新 1:将代码替换为独立构建的代码以使其更清晰

更新 2:部分修复了基于 @Jarod42 评论的实例化问题,但仍然失败

我有一些代码想要以不区分大小写的方式搜索带有字符串键的字典。完整代码如下。

所示代码编译、链接和工作,没有任何警告、错误或问题。

如果我取消注释显式实例化模板的行,那么我会得到 ​​p>

警告 C4667:'const std::_Tree_const_iterator>>> findKeyIC(const MyMap &,const std::wstring &)':未定义与强制实例化匹配的函数模板

另外,在调用 findKeyIC intellisense 的 FindNameMyMapIC 行中会抱怨:

E0304 没有函数模板“findKeyIC”的实例与参数列表参数类型匹配:(const MyMap, const std::wstring)

我对 Intellisense 问题最感兴趣,但觉得显式实例化问题可能是相关的。

#include <boost/algorithm/string.hpp>
#include <map>

typedef std::map<std::wstring, int> MyMap;
const MyMap gMyMap =   L"A", 0,  L"B", 1 ,  L"C", 2  ;

// Cases insensitive comparison of two strings, return true if they match.
// Supports std:string variants and char*/wchar*.
template<class StrType>
inline bool StrIEquals(const StrType& str1, const StrType& str2)

    return boost::iequals(str1, str2);


inline bool StrIEquals(const char* const& str1, const char* const& str2)

    return (_stricmp(str1, str2) == 0);


inline bool StrIEquals(const wchar_t* const& str1, const wchar_t* const& str2)

    return (_wcsicmp(str1, str2) == 0);


// Returns an iterator that refers to the location of an element in a map that has a key equivalent
// to a specified key using case insensitive comparison.
template <typename Key, typename Value, typename Reference, template<typename ...> class Container>
inline auto findKeyIC(const Container<Key, Value>& container, Reference const& key)

    auto  it = container.cbegin();
    for (; it != container.cend(); ++it)
    
        if (StrIEquals((const Key)it->first, (const Key)key))
            return it;
    
    return it;


// template const MyMap::const_iterator findKeyIC(const MyMap& container, const std::wstring& key);

int FindNameMyMapIC(const std::wstring& name)

    auto it = findKeyIC(gMyMap, name);
    if (it != gMyMap.cend())
    
        return it->second;
    
    return -1;

【问题讨论】:

我尝试用 'typename MyMap::const_iterator' 替换模板定义中的 auto 和显式实例化,但它的行为方式相同。 明确地图模板参数比较和分配似乎可以解决智能感知问题,并结合使用显式 const_iterator(上一条评论)将具有显式实例化的探针转换为智能感知警告(函数定义为'findKeyIC' 未找到) 意识到我仍然误解了您如何进行显式实例化, 产生智能感知警告但没有错误的显式实例化是:模板类型名 MyMap::const_iterator findKeyIC(const MyMap& container, std::wstring const& key); 完全明确比较和分配器不会改变这一点 【参考方案1】:

我有这段代码来显式实例化模板:

MyMap::const_iterator findKeyIC(const MyMap& container, const std::wstring& key);

不,你声明了非模板函数重载。

我认为智能感知会受到“可变参数”容器的干扰,而 std::map 则不会。

如果可能,我会更改您的地图比较器以比较不区分大小写,因此您可以使用map::find(对数查找而不是线性搜索)

否则,您可能会这样做:

// Returns an iterator that refers to the location of an element in a map that has a key equivalent
// to a specified key using case insensitive comparison.
template <typename Key, typename Container>
auto findKeyIC(const Container& container, Key const& key)

    return std::find_if(container.cbegin(), container.cend(),
                        [&](const auto& p) return StrIEquals(p.first, key); );

【讨论】:

噢!感谢您发现显式实例化问题,这误导了我。有了这个固定的智能感知,就会像另一个例子一样抱怨。 我试图修复显式实例化并且新代码不起作用,尽管它至少现在抱怨在显式实例化期间无法匹配模板,并且可能提供了 Intellisense 失败原因的线索.我已经更新了问题,希望能让事情更清楚 感谢关于 find_if 的建议,我没遇到过【参考方案2】:

可以通过用显式类型替换模板定义中的 auto 并显式列出 std:map 模板可选参数 Compare 来修复 Intellisense 错误>分配器.

因此那部分代码变成:

// Returns an iterator that refers to the location of an element in a map that has a key equivalent
// to a specified key using case insensitive comparison.
template <typename Key, typename Value, typename Reference, class Compare, class Allocator, template<typename ...> class Container>
inline typename Container<Key, Value, Compare, Allocator>::const_iterator findKeyIC(const Container<Key, Value, Compare, Allocator>& container, Reference const& key)

    auto  it = container.cbegin();
    for (; it != container.cend(); ++it)
    
        if (StrIEquals((const Key)it->first, (const Key)key))
            return it;
    
    return it;


template typename MyMap::const_iterator findKeyIC(const MyMap& container, std::wstring const& key);

此代码编译和链接时没有编译器警告或错误,也没有智能感知错误。

但是,它会在显式模板实例化行中的 findKeyIC 上留下智能感知警告。

找不到“findKeyIC”的函数定义。

【讨论】:

为什么要显式实例化? TBH 我现在不需要它,我这样做是为了帮助诊断我遇到的问题。现在我已经成功地构建了它,没有智能感知或编译器错误,我可以忽略它。

以上是关于如何对复杂的模板化函数进行显式实例化?和相关的 Intellisense 错误的主要内容,如果未能解决你的问题,请参考以下文章

MSVC:显式模板实例化失败,而隐式实例化成功

使用模板化成员函数显式实例化模板类

显式实例化模板类的显式实例化模板方法

函数申明对函数模板实例化的屏蔽

用于实例化模板代码的显式习惯用法 - 不包括其源代码

将 pimpl 与 Templated Class 和显式实例化的模板一起使用