使用可变参数模板进行隐式转换
Implicit conversions with variadic templates
考虑两个函数调用
foo({"a", 1}, {"b", "value"});
foo({"a", 1}, {"b", "value"}, {"c", 1.0});
有没有办法为任意数量的参数对编写函数foo
?
我在想一些类似的事情
template <typename... Args>
void foo(std::pair<const char*, Args>&&...);
不幸的是,这不起作用。
GCC 失败并显示错误:
error: too many arguments to function 'void foo(std::pair<const char*, Args>&& ...) [with Args = {}]'
foo({"aa", 1});
尝试简化一下您的示例并考虑一下:
#include<utility>
template<typename T>
void foo(std::pair<char*, T>) {}
int main() {
foo({"a", 1});
}
如您所见,它无法编译。
问题是{ "a", 1 }
不是std::pair
,即使你可以从中构造一个
#include<utility>
void foo(std::pair<char*, int>) {}
int main() {
foo({"a", 1});
}
错误很明显:
无法推断模板参数"T">
你为什么不能?
一旦知道T
,编译器就可以构造这样的一对。无论如何,必须推导T
,编译器无法做到这一点{ "a", 1 }
因为这不是可以推导它的对。
无论如何,{ "a", 1 }
可以转换为一对,在特定情况下转换为std::pair<char *, T>
的专业化,但首先必须推断出T
。
从什么推导?当然是一对,但你还没有一对。
依此类推,在一个循环中。
现在让我们讨论一下你尝试做一些涉及可变参数模板的类似事情:不用说,如果上面显示的更简单的例子不能编译,它的可变参数扩展(如果有的话)也不会编译,原因或多或少是相同的。
有没有办法为任意数量的参数对编写函数foo?
我会说不,除非你使用对作为foo
的参数.
它遵循一个最小的工作示例:
#include<utility>
template <typename... Args>
void foo(std::pair<const char*, Args>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair("b", "value"));
}
如果你愿意,你也可以推导出第一个参数,只要它的类型是固定的:
#include<utility>
template <typename T, typename... Args>
void foo(std::pair<T, Args>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair("b", "value"));
}
否则,如果未修复,您可以执行此操作:
#include<utility>
template <typename... First, typename... Second>
void foo(std::pair<First, Second>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair(0, "value"));
}
有没有办法为任意数量的参数编写函数foo。 对?
有一些基于可变参数模板的解决方案,但参数必须是成对的,以允许编译器推断类型。那么这样的事情可能会起作用:
template<typename... Args>
void foo() {}
template<typename T, typename U, typename... Args>
void foo(const std::pair<T, U>& p, Args... args) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
foo(args...);
}
所以对于:
foo(std::make_pair("a", 1), std::make_pair("b", "value"), std::make_pair("c", 1.0));
输出(使用 clang 3.8)为:
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = int, Args = <std::__1::pair<const char *, const char *>, std::__1::pair<const char *, double>>]
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = const char *, Args = <std::__1::pair<const char *, double>>]
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = double, Args = <>]
这是完整的工作示例。
要扩展一下 Edgar Rokyan 的答案,您可以将对创建移动到foo
函数中:
template<typename... Args>
void foo() {}
// Forward declaration
template<typename U, typename... Args>
void foo(const char * str, U u, Args... args);
// When given a pair
template<typename U, typename... Args>
void foo(const std::pair<const char *, U>& p, Args... args) {
std::cout << p.first << " = " << p.second << std::endl;
foo(args...);
}
// when given a C string and something else, make a pair
template<typename U, typename... Args>
void foo(const char * str, U u, Args... args) {
foo(std::make_pair(str, u), args...);
}
然后你可以这样称呼它:
foo("hi", 42,
"yo", true,
std::make_pair("Eh", 3.14),
"foo", false,
some_pair);
在 c++17 中,您可以通过使用构造函数的模板推导来解决此问题并欺骗编译器:
#include <iostream>
#include <utility>
template <class... Args>
struct P:std::pair<Args...> {
P(Args... args):std::pair<Args...>(args...) { }
};
template <class... Args>
void foo(std::pair<const char *, Args>&&...) {
}
int main() {
foo(P{"abc", 1}, P{"abc", "abc"}, P{"abc", 2.0});
}
[现场演示]
- 如何将 std::filesystem::p ath 转换为 LPCSTR,以便在 LoadLibrary() 变体之一
- 如何使用可变参数模板强制转换每个变体类型
- 如何将 boost::hana::tuple 转换为 std::变体
- std::转换move构造函数的模板专业化的变体
- 将STD ::变体转换为STD ::模板类实例的元组
- 为什么我的变体将 std::string 转换为布尔值
- 如何将COM实例转换为变体,以将其传递给IDISPACH INDOKE
- 将元组转换为变体
- C++,将向量<specific_type>转换为向量<提升::变体>
- C++变体:为什么转换构造函数需要大小.(类型)为非零
- 将两个uint32_t转换为uint64_t,然后根据位模式而不是值变回双精度
- C++变体用bool转换构造函数
- 将变体、矢量<variant>和矢量<矢量<variant>>转换为我选择的等效类型
- 协变返回类型无效的转换错误
- 协变返回类型和类型转换
- 变体浮点数到双精度值转换,四舍五入到小数点后 1 位
- 变分函数指针转换
- 我已经在我的运算符 [] 中使用了一个代理来隐式转换 boost::变体。如何通过运算符 [] 维护分配?
- 如何使用具有模板转换运算符的非模板代理对象来避免指定boost::变体的类型
- 除了转换char*之外,还有更好的方法来获得一个变量值吗?