- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要创建一个尽可能通用的函数,假设我有几个 map
s 一起工作 --
int main()
{
map<int, string> m1 = {{0, "abc"}, {1, "def"}, {2, "ghi"}} ;
map<int, double> m2 = {{0, 0.5}, {1, 0.6}, {2, 0.7}} ;
map<int, vector<string>> m3 = {{0, {"abc", "def"}},
{1, {"ghi", "ijk"}}};
dosomething(m1);
dosomething(m2);
}
和我的 template
d dosomething()
函数看起来像这样——
template <typename A, typename B>
void dosomething(map<A,B> m)
{
for(auto e : m)
{
// do something with e
}
}
现在,如果我想编写一个适用于任何类型的 map
的函数(即 map<int, vector<string>
或 map<int, string>
或 map<int, double>
)我该怎么做?如果我能做这样的事情那就太好了 --
template <typename A, typename B>
void dosomething(map<A,B> m)
{
for(auto me: m)
{
if (the type of B is not a standard container type)
{
// do something with me.second
}
else if(the type of B is a something from the standard container)
{
for(int i = 0 ; i < (me.second).size() ; i++)
// do something with me.second[i]
}
}
}
我如何在 C++ 中做到这一点?我假设编译器遵循 c++11 规范。
最佳答案
模板实例化中的代码是为了编译。因此,当根据模板参数的类型做不同的事情时,您通常不能将它们放在一个函数中。相反,您会将处理委托(delegate)给适当重载的函数,该函数本身可能是有条件适用的模板。例如,您的 dosomething()
函数可能如下所示:
// suitable declaration/definition of dosomething_apply() go here; see below
template <typename A, typename B>
void dosomething(std::map<A, B> const& m) {
for (auto&& me: m) {
dosomething_apply(me.second);
}
}
顺便说一句:不要使用for (auto e: m)
除非您有充分的理由需要此表格!在大多数情况下,这是一个性能问题。同样,您不应按值传递更大的对象,而应使用合适的引用类型传递它们。
有点棘手的事情是确定参数是否为 dosomething_apply()
是否是标准容器:当然没有类型特征将所有标准分类为这样。不过,可以创建相应的类型特征。下一个问题是这是否真的是您想要检测的,因为您在元素上使用索引的假设布局意味着 me.second
有一个基于索引的下标运算符,仅对 std::vector<...>
为真, std::dequeue<...>
, std::basic_string<...>
, std::array<...>
, 和 std::bitset<...>
(不确定这是否是提供下标的完整容器集)。还有其他容器不进行下标操作,例如std::list<...>
, std::map<...>
, std::unordered_map<...>
等
不过,所有这些容器(std::bitset<...>
除外)都提供迭代器接口(interface)。在 dosomething_apply()
的实现中检测一个类型是否提供迭代器接口(interface)并使用该接口(interface)可能更合理.由于您似乎设置为使用基于索引的下标,因此下面的示例处理了上面提到的类模板集。
第一步是创建一个合适的特征类,它检测需要特殊处理的所需类型。在许多情况下,可以检测到是否存在合适的成员函数或成员类型。由于您特别要求标准类型,因此有必要列出支持的类型,因为也可以检测非标准类的成员函数或成员类型。这是一个名为 is_subscripted
的示例特征类:
template <typename T>
struct is_subscripted: std::false_type {};
template <typename T, std::size_t N>
struct is_subscripted<std::array<T, N>>: std::true_type {};
template <std::size_t N>
struct is_subscripted<std::bitset<N>>: std::true_type {};
template <typename cT, typename Al>
struct is_subscripted<std::deque<cT, Al>>: std::true_type {};
template <typename cT, typename Tr, typename Al>
struct is_subscripted<std::basic_string<cT, Tr, Al>>: std::true_type {};
template <typename cT, typename Al>
struct is_subscripted<std::vector<cT, Al>>: std::true_type {};
它只是创建了一个默认版本的 trait,声明该 trait 与 std::false_type
的派生不匹配。 .然后相应的模板专门用于上面列出的类模板,每个模板都来自 std::true_type
。 .这样一个形式的表达式 is_specialized<T>::value
可用于检测特征是否适用于类型 T
.
下一步是提供合适的处理函数。由于特征存在或不存在,使用 enable_if_t<...>
是一个简单的方法:
template <typename T>
std::enable_if_t<!is_subscripted<T>::value>
dosomething_apply(T const& value) {
std::cout << "value=" << value << '\n';
}
template <typename T>
std::enable_if_t<is_subscripted<T>::value>
dosomething_apply(T const& range) {
for (auto size(range.size()), i(size - size); i != size; ++i) {
std::cout << "range=" << range[i] << '\n';
}
}
使用 std::enable_if_t<Value>
用Value
评估为 true
产量 void
(使用第二个参数,例如 std::enable_if_t<Value, double>
以获得不同的类型)并且函数模板变得适用。与 Value
一起使用评估为 false
不产生类型并且函数模板被忽略(有关正在发生的事情的解释,请参阅 SFINAE)。
... 就是这样。把一个合适的程序放在一起所需要的一切,一切都应该有效。下面是一个完整的程序,可以提供给 C++14 编译器。上面的代码中有一些 C++14 的次要用途,例如使用 std::enable_if_v<T>
而不是 typename std::enable_if<T>::type
.如果您需要通过适用于先前 C++ 标准的编译器传递代码,那么将 C++14 用法替换为 C++11 用法应该相对简单。
#include <map>
#include <iostream>
#include <utility>
#include <array>
#include <bitset>
#include <deque>
#include <string>
#include <vector>
// ----------------------------------------------------------------------------
template <typename T>
struct is_subscripted: std::false_type {};
template <typename T, std::size_t N>
struct is_subscripted<std::array<T, N>>: std::true_type {};
template <std::size_t N>
struct is_subscripted<std::bitset<N>>: std::true_type {};
template <typename cT, typename Al>
struct is_subscripted<std::deque<cT, Al>>: std::true_type {};
template <typename cT, typename Tr, typename Al>
struct is_subscripted<std::basic_string<cT, Tr, Al>>: std::true_type {};
template <typename cT, typename Al>
struct is_subscripted<std::vector<cT, Al>>: std::true_type {};
// ----------------------------------------------------------------------------
template <typename T>
std::enable_if_t<!is_subscripted<T>::value>
dosomething_apply(T const& value) {
std::cout << "value=" << value << '\n';
}
template <typename T>
std::enable_if_t<is_subscripted<T>::value>
dosomething_apply(T const& range) {
for (auto size(range.size()), i(size - size); i != size; ++i) {
std::cout << "range=" << range[i] << '\n';
}
}
// ----------------------------------------------------------------------------
template <typename A, typename B>
void dosomething(std::map<A, B> const& m)
{
for (auto&& me: m) {
dosomething_apply(me.second);
}
}
int main()
{
dosomething(std::map<int, int>{ { 1, 2 }, {3, 4 } });
dosomething(std::map<int, std::array<int, 2> >{ { 1, { { 2, 3 }} }, {4, { { 5, 6 } } } });
dosomething(std::map<int, std::bitset<4> >{ { 1, std::bitset<4>("1010") }, {2, std::bitset<4>("0011") } });
dosomething(std::map<int, std::deque<int>>{ { 10, { { 12, 13, 14 } } }, { 20, { 22, 23, 24 } } });
dosomething(std::map<int, std::string>{ { 1, "one" }, {2, "two" } });
dosomething(std::map<int, std::vector<int>>{ { 30, { { 32, 33, 34 } } }, { 40, { 42, 43, 44 } } });
}
关于c++使用模板制作最通用的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26643900/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!