模板函数中具有单个可选参数和默认值的函数
我想要一个只有 1 个参数的函数,该参数对于泛型类型是可选的,并且已指定 boost::none
作为默认值。这可能吗?
#include <iostream>
#include <string>
#include <boost/optional.hpp>
template <typename T>
void f(boost::optional<T> v = boost::none)
{
if (v)
{
std::cout<<"v has value: " << v.get();
}
else
{
std::cout<<"v has no value!";
}
}
int main()
{
f(12);
f("string");
return 0;
}
I want a function with has only 1 argument which is optional with generic type and has assigned boost::none
as default value. Is that possible?
#include <iostream>
#include <string>
#include <boost/optional.hpp>
template <typename T>
void f(boost::optional<T> v = boost::none)
{
if (v)
{
std::cout<<"v has value: " << v.get();
}
else
{
std::cout<<"v has no value!";
}
}
int main()
{
f(12);
f("string");
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
是的,这是可能的,但它不能与模板推导一起使用(
f(12)
将尝试实例化一个f
,这不会不存在)。当您像这样调用它时,您的代码将编译:或显式实例化它:
Yes, that's possible, but it doesn't work together with template deduction (
f(12)
will try to instantiate af<int&&>
, which doesn't exist). Your code will compile when you call it like that:or explicitly instantiate it:
嗯,另一个答案是关闭。但还没有完全实现。
f(12)
不会“尝试实例化f
”。事实上,它无法推导 T,因为 T 处于非推导上下文中。另外,你的问题不是重点:即使没有默认值,你也会遇到同样的问题: Compiler Explorer
现在,在我盲目地向您展示如何解决所有这些问题之前,请先问自己一个问题:我们在这里做什么。
如果您想要默认参数,那么根据定义,这是否意味着它们不是可选值?也许您只需要: 编译器资源管理器
打印
使用一些黑客技术,您可以通过默认模板类型参数来组合重载:
打印 编译器Explorer
如果您需要
可选<>
怎么办在这种情况下,在您的特定示例中,您可能需要
可选
避免不必要地复制所有参数;但请参阅引用类型的std::可选专业化。如果您真的真的想要
,那么您必须拥有您正在寻找的语义。您不关心您将无法知道不带参数的调用与使用未初始化的可选(
none
)调用之间的区别。这有点像许多脚本语言,对吧?现在,您必须使模板参数成为推导的上下文,然后要确保...它是一个
可选
:一个“优点”是现在您可以清楚地看到正在完成复制。
另一个“优势”是,现在您可以以同样的方式支持
std::Optional
: https ://godbolt.org/z/1Mhja83Wo总结
我希望这个答案能够说明 C++ 不是动态类型语言。这意味着“未知”类型的可选参数的想法实际上并不惯用。 (可能有点不幸的是,Boost 将其称为
boost::none
而不是std::nullopt
,这可能会让人们将其与 Python 的None
联系起来>.)相反,您可以使用 静态多态性。最简单的版本是我展示的第一个版本,使用函数重载。
如果您要模仿 C++ 中的动态类型接口,您可能会使用
std::variant
或std::any
来代替。要限制绑定类型,您可以使用概念(这有点深,但请参阅“Boost Type Erasure”)。1 我真的真的真的很想玩之字形啊
Mmm the other answer is close. But not quite there.
f(12)
doesn't "try to instantiatef<int&&>
". In fact, it fails to deduce T because T is in non-deduced context.Also, your question was beside the point: even without a default value you have the same problem: Compiler Explorer
Now, before I blindly show you how you can fix all that, ask yourself the question: What are we doing here.
If you want default arguments, doesn't that by definition mean that they aren't optional values? Maybe you simply need: Compiler Explorer
Printing
With some hackery you can combine the overloads by defaulting the template type argument:
Prints Compiler Explorer
What If You Require
optional<>
In that case, in you specific example you would probably want
optional<T const&>
to avoid needlessly copying all the arguments; but see std::optional specialization for reference types.If You Really Really Want¹
Say, you MUST have the semantics you were looking for. You do not care that you won't be able to know the difference between calling with no argument vs. calling with an uninitialized optional (
none
). This is kinda like many scripting languages, right?Now you have to make the template argument become deduced context, and then want to ensure that... it is an
optional<T>
:One "advantage" is that that now you clearly see the copying being done.
Another "advantage" is that now you can support
std::optional
the same way: https://godbolt.org/z/1Mhja83WoSummary
I hope this answer gets the point across that C++ is not a dynamically typed language. This implies that the idea of optional arguments of "unknown" type is really not idiomatic. (It might be a bit unfortunate that Boost called it
boost::none
instead of e.g.std::nullopt
, perhaps giving people associations with Python'sNone
.)Instead, you can use static polymorphism. The simplest version of that was the first I showed, using function overloading.
If you were to mimic a dynamic type interface in C++, you would probably use
std::variant
orstd::any
instead. To restrict the bound types you would use concepts (this is getting a bit deep, but see e.g. Boost Type Erasure).¹ i really really really wanna zig a zig ah