C++ require 没有隐式转换的函数
我使用 boost::variant
来模仿具有值语义的继承。
有一个类可以被打印:
struct Printable { /* ... */ };
void print(const Printable &) { /* ... */ }
和类可能不会:
struct NotPrintable { /* ... */ };
最后,有一个带有隐式强制转换的“Base
”类:
struct Base : boost::variant<Printable, NotPrintable>
{
Base(const Printable &) {} // constructor for implicit cast
Base(const NotPrintable &) {} // constructor for implicit cast
};
// Print, if printable, throw exception, if not
void print(const Base &base)
{
Printer printer{};
base.apply_visitor(printer);
}
问题是如何检查访问者内部是否可打印:
struct Printer
{
using result_type = void;
// If printable
template<typename PrintableType> requires
requires(const PrintableType &v) { {print(v)}; } // (1)
void operator()(const PrintableType &v) { print(v); }
// If not printable
void operator()(const auto &v) { throw /*...*/; }
};
要求 由于隐式转换为
始终为 true。如何避免只在那个确切的地方进行转换?const Base &
,(1)
I'm using boost::variant
to imitate inheritance with value semantics.
There is one class that may be printed:
struct Printable { /* ... */ };
void print(const Printable &) { /* ... */ }
And class that may not:
struct NotPrintable { /* ... */ };
Finally, there is "Base
" class with implicit cast:
struct Base : boost::variant<Printable, NotPrintable>
{
Base(const Printable &) {} // constructor for implicit cast
Base(const NotPrintable &) {} // constructor for implicit cast
};
// Print, if printable, throw exception, if not
void print(const Base &base)
{
Printer printer{};
base.apply_visitor(printer);
}
The problem is how to check for printable inside of visitor:
struct Printer
{
using result_type = void;
// If printable
template<typename PrintableType> requires
requires(const PrintableType &v) { {print(v)}; } // (1)
void operator()(const PrintableType &v) { print(v); }
// If not printable
void operator()(const auto &v) { throw /*...*/; }
};
Requirement (1)
is always true due-to implicit conversion to const Base &
. How to avoid conversion only in that exact place?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如@Jarod42在评论中所说,为了保证不发生隐式转换,需要定义一个模板
print()
函数来“吸收”其他类型(NotPrintable 在您的示例中)并将其设置为删除
然后可以将
printable
概念定义为要求表达式
print(x)
格式良好。当
T
的类型为Printable
或Base
时,表达式print(x)
有效,因为您已定义相应的print()
函数。当T
的类型为NotPrintable
或其他类型时,将调用删除的print()
,这使得表达式格式错误,因此约束条件不满足。然后你可以使用这个概念来约束
Printer::operator()
请注意,由于
print(const auto&)
可以实例化为任何类型,这将禁止所有隐式转换,但我们仍然可以通过添加约束来允许某些隐式转换As @Jarod42 said in the comments, in order to ensure that implicit conversion does not occur, you need to define a template
print()
function to "absorb" other types (NotPrintable
in your example) and set it to deleteThen the
printable
concept can be defined aswhich requires the expression
print(x)
to be well-formed.When the type of
T
isPrintable
orBase
, the expressionprint(x)
is valid since you have defined the correspondingprint()
function for them. When the type ofT
isNotPrintable
or other types, the deletedprint()
will be invoked which makes the expression ill-formed, so that the constraint is not satisfied.Then you can use this concept to constrain
Printer::operator()
Note that since
print(const auto&)
can be instantiated to any type, this will prohibit all implicit conversions, but we can still allow some implicit conversions by adding constraints to it我找到了一个基于内联好友定义的完美解决方案。
根据标准:
其他一些可能有用的东西:
删除的模板功能
缺点:
每个函数都有样板
禁止所有隐式转换更改接口
缺点:
Base + Base
->Base::add(Base, Base)
)缺点:
Boolean + Integer
)?I found a perfect solution that is based on Inline friend definition.
According to standard:
Some other things that may work:
Deleted template function
cons:
Boilerplate for every function
Forbids all implicit conversionsChange interface
cons:
Base + Base
->Base::add(Base, Base)
)cons:
Boolean + Integer
)?