注意:以下代码是根据以下信息进行修改的:https://stackoverflow.com/a/27375389
#include <iostream>
#include <type_traits>
template<class Head>
void print_args(std::ostream& s, Head&& head) {
s << std::forward<Head>(head);
}
template<class Head, class... Tail>
void print_args(std::ostream& s, Head&& head, Tail&&... tail) {
if (std::is_same<Head, uint8_t>::value)
s << static_cast<int>(head) << ","; // cast uint8_t so that the value of 1 or 0 can be displayed correctly in console
else
s << std::forward<Head>(head) << ",";
print_args(s, std::forward<Tail>(tail)...);
}
template<class... Args>
void print_args(Args&&... args) {
print_args(std::cout, std::forward<Args>(args)...);
}
int main()
{
uint8_t val = 1;
print_args(std::string("hello"), val); // error: invalid static_cast from type 'std::basic_string<char>' to type 'int'
print_args("hello", val); // error: invalid static_cast from type 'const char [6]' to type 'int'
}
问题>我需要将uint_8
强制转换为int
,以便可以在控制台中正确显示该值。但是,以上代码在std::string
或const char*
上均存在构建问题。
该功能的解决方法是什么?
答案 0 :(得分:5)
.dropdown-menu {
display : none !important;
}
.dropdown-menu.show {
display : block !important;
}
是在运行时求值的,因此编译器必须为其编译两个分支,而if
不能针对非算术类型(例如static_cast<int>(head)
)进行编译。
在C ++ 17中,您可以使用std::string
进行修复。
在C ++ 17之前,添加一个可以为if constexpr(std::is_same<Head, uint8_t>::value)
重载的额外功能:
uint8_t
答案 1 :(得分:1)
您有几个问题。对于编译时问题:
if (std::is_same<Head, uint8_t>::value)
对此:
if constexpr (std::is_same<Head, uint8_t>::value)
那是因为您只希望在if强制转换为uint时编译if的主体。仅因为运行时if为false并不意味着其中的代码不必有效。 constexpr如果可以解决这个问题。
接下来,您的类型比较太严格了。将引用与非引用进行比较将返回false。因此,您想在is_same测试之前衰减类型。我也更喜欢is_same_v:
if constexpr (std::is_same_v<std::decay_t<Head>, uint8_t>)
最后,您的基本情况(最后一个元素)仍需要相同类型的“ if constexpr”才能正确打印,但您仅在主循环中应用了此逻辑。
将它们放在一起:
template<class Head>
void print_args(std::ostream& s, Head&& head) {
if constexpr (std::is_same_v<std::decay_t<Head>, uint8_t>)
s << static_cast<int>(head);
else
s << head << ",";}
template<class Head, class... Tail>
void print_args(std::ostream& s, Head&& head, Tail&&... tail) {
if constexpr (std::is_same_v<std::decay_t<Head>, uint8_t>)
s << static_cast<int>(head) << ",";
else
s << head << ",";
print_args(s, std::forward<Tail>(tail)...);
}
template<class... Args>
void print_args(Args&&... args) {
print_args(std::cout, std::forward<Args>(args)...);
}
您可以将constexpr的公共属性分解为单个辅助函数,以减少冗余代码,使其保持DRY。但是,除了去那里,我会提出其他建议。
仅使其工作并不总是最好的目标。递归模板可以在编译器中使用更多的内存,并降低构建速度,因此,如果避免产生递归的结果相同,则避免递归的解决方案会更好。
这样,考虑一个fold表达式(c ++ 17)和一个lambda来打印代码:
以上所有内容均可替换为此:
template<class... Args>
void print_args(Args&&... args) {
([](auto&& arg)
{
if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, uint8_t>)
std::cout << static_cast<int>(std::forward<Args>(arg));
else
std::cout << arg;
if (sizeof...(Args) > 1)
std::cout << ",";
}(args), ...);
}
简而言之,它使用逗号运算符上的fold表达式,使用形式为(f(x)op ...)的IILE(立即调用的Lambda表达式),其中f(x)是lambda(给定当前的arg),“ op”是用于对调用进行排序的逗号运算符。)第二个“ if”防止尾部逗号。
答案 2 :(得分:0)
一种可能的解决方案:
#include <iostream>
#include <type_traits>
namespace detail
{
namespace cpp11
{
template<class arg>
void print(std::ostream& s, arg&& a, typename std::enable_if<std::is_same<typename std::remove_reference<typename std::remove_cv<arg>::type>::type, uint8_t>::value>::type* =0)
{
s << static_cast<int>(a) << ",";
}
template<class arg>
void print(std::ostream& s, arg&& a, typename std::enable_if<!std::is_same<typename std::remove_reference<typename std::remove_cv<arg>::type>::type, uint8_t>::value>::type* =0)
{
s << std::forward<arg>(a) << ",";
}
}
namespace cpp14
{
template<class arg>
void print(std::ostream& s, arg&& a, std::enable_if_t<std::is_same<typename std::remove_reference<typename std::remove_cv<arg>::type>::type, uint8_t>::value>* =0)
{
s << static_cast<int>(a) << ",";
}
template<class arg>
void print(std::ostream& s, arg&& a, std::enable_if_t<!std::is_same<typename std::remove_reference<typename std::remove_cv<arg>::type>::type, uint8_t>::value>* =0)
{
s << std::forward<arg>(a) << ",";
}
}
namespace cpp17
{
template<class arg>
void print(std::ostream& s, arg&& a)
{
if constexpr (std::is_same_v<std::remove_reference_t<std::remove_cv_t<arg>>, uint8_t>)
s << static_cast<int>(a) << ",";
else
s << std::forward<arg>(a) << ",";
}
}
namespace cpp20
{
template<class arg>
void print(std::ostream& s, arg&& a)
{
if constexpr (std::is_same_v<std::remove_cvref_t<arg>, uint8_t>)
s << static_cast<int>(a) << ",";
else
s << std::forward<arg>(a) << ",";
}
}
template<class Head>
void print_args(std::ostream& s, Head&& head)
{
//cpp11::print(s, std::forward<Head>(head));
//cpp14::print(s, std::forward<Head>(head));
//cpp17::print(s, std::forward<Head>(head));
cpp20::print(s, std::forward<Head>(head));
}
template<class Head, class... Tail>
void print_args(std::ostream& s, Head&& head, Tail&&... tail)
{
print_args(s, std::forward<Head>(head));
print_args(s, std::forward<Tail>(tail)...);
}
}
template<class... Args>
void print_args(Args&&... args)
{
detail::print_args(std::cout, std::forward<Args>(args)...);
}
int main()
{
uint8_t val = 1;
print_args(std::string("hello"), val);
print_args("hello", val);
}
其他一些注释:
uint8_t
,但是对于其他POD类型,例如int8_t
,byte
等,您也可能会遇到问题。std::ostream
返回template<...> std::ostream& print(...) {...; return s;}
参数std::remove_cvref{_t}
和std::remove_cv{_t}
轻松实现std::remove_reference{_t}