我想解压缩可变参数模板包,并根据包中的每种类型选择特定的重载。
我有3个重载来解压各种类型:
// fixed size char arrays
template<size_t N, typename... Ts>
void unpack(const char (&)[N], Ts&&... ts);
// char pointers
template<typename... Ts>
void unpack(const char*, Ts&&... ts);
// all other types
template<typename T, typename... Ts>
void unpack(T&&, Ts&&... ts);
我将一个char数组(char buf[1024]
)作为左值传递给可变参数构造函数。打开包装时,正在选择T&&
重载。
如何选择const char (&)[N]
或const char*
重载?
示例应用
#include <iostream>
struct foo
{
template<typename... Ts>
foo(Ts&&... ts)
{
unpack(std::forward<Ts>(ts)...);
}
template<size_t N, typename... Ts>
void unpack(const char (&)[N], Ts&&... ts)
{
std::cout << "const T (&)[N]" << std::endl;
unpack(std::forward<Ts>(ts)...);
}
template<typename... Ts>
void unpack(const char*, Ts&&... ts)
{
std::cout << "const char*" << std::endl;
unpack(std::forward<Ts>(ts)...);
}
template<typename T, typename... Ts>
void unpack(T&&, Ts&&... ts)
{
std::cout << "T&&" << std::endl;
unpack(std::forward<Ts>(ts)...);
}
void unpack()
{
}
};
int main()
{
char buf[1024];
const char* str = "foo";
foo f(buf, str);
return 0;
}
以上代码会打印以下内容:
T&&
const char*
我想要打印:
const T (&)[N]
const char*
或
const char*
const char*
ie:选择两个char重载中的一个 - 数组或指针。
答案 0 :(得分:5)
void unpack(T&&, Ts&&... ts)
是因为char
数组中的buf
不是const
。
如果将buf
更改为char const buf[1024]{};
,编译器会告诉您调用不明确,这是朝着正确方向迈出的一步。从那里你可能需要使用SFINAE(例如std::is_array
),std::decay
或其他一些方法来消除呼叫的歧义。
答案 1 :(得分:1)
您可以使用以下内容:
template<typename T, typename... Ts>
typename std::enable_if<!std::is_array<typename std::remove_reference<T>::type>::value>::type
unpack(T&&, Ts&&... ts)
{
std::cout << "T&&" << std::endl;
unpack(std::forward<Ts>(ts)...);
}
注意:目前禁止任何数组,而不仅仅是char数组。
答案 2 :(得分:1)
一种可能是删除数组重载并使用
template<typename T, typename... Ts>
std::enable_if_t<std::is_same<std::decay_t<T>, char>::value> unpack(T*, Ts&&... ts)
{
std::cout << "(const) char*" << std::endl;
unpack(std::forward<Ts>(ts)...);
}
仅当T
被推断为(可能是cv限定的)char
时才启用此功能(这意味着它与char *
和const char *
完全匹配参数),在这些情况下,它比基本模板更专业,因此通过重载决策选择。
如果不使用C ++ 14,请将enable_if_t
和decay_t
替换为更详细的typename /*...*/::type
。
答案 3 :(得分:0)
根据您的需要,您可以检查是否与之前的重载匹配,而不是专门测试数组/指针:
int unpack_helper(...);
// fixed size char arrays
template<size_t N, typename... Ts>
void unpack_helper(const char (&)[N], Ts&&... ts);
// char pointers
template<typename... Ts>
void unpack_helper(const char*, Ts&&... ts);
// fixed size char arrays
template<size_t N, typename... Ts>
void unpack(const char (&)[N], Ts&&... ts);
// char pointers
template<typename... Ts>
void unpack(const char*, Ts&&... ts);
// all other types
template<typename T, typename... Ts, size_t = sizeof(unpack_helper(std::declval<T&&>(), std::declval<Ts&&>()...))>
void unpack(T&&, Ts&&... ts);
这有可能带来的好处,也可能是使用转换运算符选择早期函数重载的类类型的缺点。