模板类型推导:通过typedef进行区分

Template type deduction: distinguish by typedef

本文关键字:typedef 行区 通过 类型      更新时间:2023-10-16

如何通过typedef区分模板参数?

情境:我有几种类型的列表(实现为向量)。我有一个特殊的StringList,我想用不同的方式处理它。

typedef std::vector<std::string> StringList;
inline void f(StringList const& list) {
  ...
}
template <typenamte T>
inline void f(std::vector<T> const& list) {
  ...
}

在我的变量定义为StringList的情况下,我希望调用第一个版本,而当变量定义为std::vector<std::string>时,我希望调出第二个版本。但StringListstd::vector<std::string>调用第一个版本。使用using可以得到相同的行为。

如果这不是可行的,那么一个合理的解决方案就很好了。

当然,扩展std::vector<std::string>会有所帮助,但由于这根本不是一个好主意,我不知道如何区分它们。

您至少有三个选项:

#include <vector>
#include <string>
// option 1
struct StringList : std::vector<std::string>
{
    // optionally forward the constructors of std::vector that are called
};
// option 2
struct String : std::string
{
    // optionally forward the constructors of std::string that are called
};
typedef std::vector<String> StringList;
// option 3
struct StringTag
{
};
typedef std::allocator<StringTag> StringAllocator;
typedef std::vector<std::string, StringAllocator> StringList;

第一个和第二个选项都需要转发基类的一些构造函数。第二个选项可能更好,因为假设在向字符串列表中添加字符串时可能只需要转发std::string复制构造函数。

第三种选择是我最喜欢的——部分原因是这是一种狡猾的黑客攻击,但也因为它不需要继承或转发。它之所以有效,是因为从未使用过std容器中分配器模板参数的T参数。

EDIT:C++标准意味着分配器的value_type必须与容器的value_type匹配,因此只有在标准库实现允许的情况下才能使用第三个选项。如果不允许,我建议使用第一个或第二个选项。

EDIT 2:另请参阅:如果标准容器元素类型和std::分配器类型不同,这是错误的吗?

好吧,这是解决您问题的快速而肮脏的解决方案:

struct StringList : std::vector<std::string>
{};

现在,您的函数将被正确调用。我不推荐它,但如果没有更多的信息,很难给出更好的答案。此外,请阅读从C++STL容器派生是否存在任何真正的风险?了解所涉及的风险和问题。但是,正如我在评论中所说,我建议把它们包装在课堂上。