提问人:Michel 提问时间:3/11/2023 更新时间:3/11/2023 访问量:70
是否可以使用转换或演绎指南获得模板函数来推断模板参数的类型?
Is it possible to get a template function to deduce the type of a template argument using either conversion or deduction guide?
问:
是否可以让编译器使用类型转换或推导来推断模板函数调用的类型? 如果没有,为什么不呢?
#include <iostream>
template<typename T>
class Wrapper
{
public:
Wrapper(T&& elmt)
: m_data(std::forward<T>(elmt))
{ }
const T& data() const
{
return m_data;
}
private:
T m_data;
};
template<typename T>
Wrapper(T&& elmt) -> Wrapper<T>;
template<typename T>
void someFunc(const Wrapper<T>& wrapper)
{
std::cout << wrapper.data() << std::endl;
}
int main()
{
// Any chance this could work?
// someFunc("Make me a Wrapper<const char*> please!"); //fails
// someFunc({"Make me a Wrapper<const char*> please!"}); //fails
// This works, but that's what I'd like to avoid
someFunc(Wrapper{"This one works"});
return 0;
}
(编译器资源管理器链接:https://godbolt.org/z/eGs3raMY4)
如果 Wrapper 不是模板,这将直接起作用:
#include <iostream>
class StrWrapper
{
public:
StrWrapper(const char* str)
: m_data(str)
{ }
const char* data() const { return m_data; }
private:
const char* m_data;
};
void strFunc(const StrWrapper& wrapper)
{
std::cout << wrapper.data() << std::endl;
}
int main()
{
strFunc("This works, right?");
return 0;
}
(编译器资源管理器:https://godbolt.org/z/nnoaPcs91)
我知道我可以为我想要扣除的每种类型添加一个重载,但在这种情况下,这不是一个非常实用的解决方案(需要许多重载)。
答:
0赞
NathanOliver
3/11/2023
#1
与其使用包装器,不如使用包装器,然后在函数中构造一个包装器,例如someFunc
T
template<typename T>
void someFunc(T&& to_wrap)
{
Wrapper wrapper{std::forward<T>(to_wrap)};
std::cout << wrapper.data() << std::endl;
}
这允许
someFunc("Make me a Wrapper<const char*> please!");
进行编译,如此实时示例所示。
两者兼而有之的原因
someFunc("Make me a Wrapper<const char*> please!");
someFunc({"Make me a Wrapper<const char*> please!"});
失败是它们不是 的,编译器不会尝试转换参数,因此编译器无法推断出应该是什么。Wrapper
T
评论
0赞
Michel
3/11/2023
我认为这就是我不明白的地方:为什么编译器不尝试转换?我想,如果它不是模板函数,那会。是不是模板推导先发生并失败,所以没有候选函数可以尝试转换?
0赞
NathanOliver
3/11/2023
@Michel是的。模板推导不进行转换,因为参数基本上可以转换为无限数量的类型。
0赞
Michel
3/11/2023
谢谢,这是有道理的:)这让我不禁要问,我们是否应该为函数模板提供演绎指南:如果提供了演绎指南,它适用于构造函数,而构造函数是一种函数~如果能对此进行概括就好了。
0赞
NathanOliver
3/11/2023
@Michel 我们几乎已经有了,这叫做超载。您可以利用重载,例如void someFunc(const char* str) { someFunc(Wrapper{str}); }
3赞
JeJo
3/11/2023
#2
是否可以让编译器使用类型转换或推导来推断模板函数调用的类型?
你可以在这里做一个递归方法
// variable template for checking the "Wrapper<T>" type
template<typename T> inline constexpr bool is_Wrapper = false;
template<typename T> inline constexpr bool is_Wrapper<Wrapper<T>> = true;
template<typename T>
void someFunc(T&& arg)
{
if constexpr (is_Wrapper<T>) // if T == Wrapper<T>
std::cout << arg.data() << std::endl;
else // if T != Wrapper<T>, construct explicitly and pass to the someFunc()
someFunc(Wrapper<T>{ std::forward<T>(arg) });
}
这允许两者
someFunc("Make me a Wrapper<const char*> please!"); // works
someFunc(Wrapper{ "This one works" }); // works
评论