SFINAE 用户定义的转换运算符
SFINAE User-Defined-Conversion Operator
我正在尝试使用内省设计进行模板化的用户定义转换。
在 C++20 中,我可以执行以下操作:
template<typename T>
operator T() const
{
if constexpr( requires { PFMeta<T>::from_cursor(*this); } )
{
return PFMeta<T>::from_cursor(*this);
}
else
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
}
即如果定义了 PFMeta<T>::from_cursor(const struct PFCursor&)
则使用它,否则执行 memcpy。 (godbolt 中更长的示例:https://godbolt.org/z/abed1vsK3)
我喜欢这种方法,但不幸的是,这个库也需要在 C++17 上工作。
所以我一直在尝试将 SFINAE 作为概念的替代品,但这非常棘手。
我终于设法得到了类似的东西,但使用的是模板化方法 as
而不是用户定义的转换运算符本身:
template<typename T, typename = void>
struct has_from_cursor : std::false_type { };
template<typename T>
struct has_from_cursor<T, decltype( PFMeta<T>::from_cursor(std::declval<struct PFCursor>()), void() ) > : std::true_type { };
// ...
template<class T>
std::enable_if_t<has_from_cursor<T>::value, T> as() const
{
return PFMeta<T>::from_cursor(*this);
}
template<class T>
std::enable_if_t<!has_from_cursor<T>::value, T> as() const
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
我尝试了以下编译但不起作用的方法(我无法使用它进行转换):
template<typename T>
operator std::enable_if_t<has_from_cursor<T>::value, T>() const
{
return PFMeta<T>::from_cursor(*this);
}
template<typename T>
operator std::enable_if_t<!has_from_cursor<T>::value, T>() const
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
此处更长的示例:https://godbolt.org/z/5r9Mbo18h
所以两个问题:
- 对于用户定义的转换运算符,我能否有效地完成仅使用 C++17 中的 SFINAE 概念所能完成的工作?
- 有没有比类型特征 &
enable_if
更简单的方法来执行 as
方法?理想情况下,我想做一些事情,比如定义默认的模板化方法,然后在条件存在时优先选择一个专门化(即有一个定义了静态成员函数的元 class)。
谢谢!
Can I do effectively what I can do with concepts with just SFINAE in C++17 for the user defined conversion operator?
考虑到 C++17 支持 if constepr
。鉴于您已经开发了 has_from_cursor
继承自 std::true_type
或 std::false_type
的自定义类型特征,您可以将其用于 if constexp
.
我的意思是(注意:代码未经测试)
template<typename T>
operator T() const
{ // .............VVVVVVVVVVVVVVVVVVVVVVVVV
if constexpr( has_from_cursos<T>::value )
{
return PFMeta<T>::from_cursor(*this);
}
else
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
}
Is there a simpler way to do the as approach than the type traits & enable_if? Ideally I'd like to do something like define the default templated method and then have a specialisation to be preferred if the condition is there (i.e. there is a meta class with a static member function defined).
我想你可以试试 tag-dispatching...
我的意思是从 operator T()
调用 'as()',并附加一个 int
参数
template<typename T>
operator T() const
{ return as<T>(0); } // <-- call as() with a int
其中有一个 as()
特定于 from_cursos
class 已启用,接收未使用的 int
并且只是 SFINAE enabled/disabled 到 decltype()
template <typename T> // ........accept an int; best match
decltype(PFMeta<T>::from_cursor(*this)) as (int) const
{ return PFMeta<T>::from_cursor(*this); }
和一个通用的 as()
,收到一个 long
template <typename T>
T as (long) const // <-- accept a long; worst match
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
诀窍是未使用的参数:int
.
当启用专用 as()
时,如果首选因为接受 int
所以是更好的匹配。
当禁用专用 as()
时,保留通用 as()
作为 better-than-nothig 匹配。
我正在尝试使用内省设计进行模板化的用户定义转换。
在 C++20 中,我可以执行以下操作:
template<typename T>
operator T() const
{
if constexpr( requires { PFMeta<T>::from_cursor(*this); } )
{
return PFMeta<T>::from_cursor(*this);
}
else
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
}
即如果定义了 PFMeta<T>::from_cursor(const struct PFCursor&)
则使用它,否则执行 memcpy。 (godbolt 中更长的示例:https://godbolt.org/z/abed1vsK3)
我喜欢这种方法,但不幸的是,这个库也需要在 C++17 上工作。
所以我一直在尝试将 SFINAE 作为概念的替代品,但这非常棘手。
我终于设法得到了类似的东西,但使用的是模板化方法 as
而不是用户定义的转换运算符本身:
template<typename T, typename = void>
struct has_from_cursor : std::false_type { };
template<typename T>
struct has_from_cursor<T, decltype( PFMeta<T>::from_cursor(std::declval<struct PFCursor>()), void() ) > : std::true_type { };
// ...
template<class T>
std::enable_if_t<has_from_cursor<T>::value, T> as() const
{
return PFMeta<T>::from_cursor(*this);
}
template<class T>
std::enable_if_t<!has_from_cursor<T>::value, T> as() const
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
我尝试了以下编译但不起作用的方法(我无法使用它进行转换):
template<typename T>
operator std::enable_if_t<has_from_cursor<T>::value, T>() const
{
return PFMeta<T>::from_cursor(*this);
}
template<typename T>
operator std::enable_if_t<!has_from_cursor<T>::value, T>() const
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
此处更长的示例:https://godbolt.org/z/5r9Mbo18h
所以两个问题:
- 对于用户定义的转换运算符,我能否有效地完成仅使用 C++17 中的 SFINAE 概念所能完成的工作?
- 有没有比类型特征 &
enable_if
更简单的方法来执行as
方法?理想情况下,我想做一些事情,比如定义默认的模板化方法,然后在条件存在时优先选择一个专门化(即有一个定义了静态成员函数的元 class)。
谢谢!
Can I do effectively what I can do with concepts with just SFINAE in C++17 for the user defined conversion operator?
考虑到 C++17 支持 if constepr
。鉴于您已经开发了 has_from_cursor
继承自 std::true_type
或 std::false_type
的自定义类型特征,您可以将其用于 if constexp
.
我的意思是(注意:代码未经测试)
template<typename T>
operator T() const
{ // .............VVVVVVVVVVVVVVVVVVVVVVVVV
if constexpr( has_from_cursos<T>::value )
{
return PFMeta<T>::from_cursor(*this);
}
else
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
}
Is there a simpler way to do the as approach than the type traits & enable_if? Ideally I'd like to do something like define the default templated method and then have a specialisation to be preferred if the condition is there (i.e. there is a meta class with a static member function defined).
我想你可以试试 tag-dispatching...
我的意思是从 operator T()
调用 'as()',并附加一个 int
参数
template<typename T>
operator T() const
{ return as<T>(0); } // <-- call as() with a int
其中有一个 as()
特定于 from_cursos
class 已启用,接收未使用的 int
并且只是 SFINAE enabled/disabled 到 decltype()
template <typename T> // ........accept an int; best match
decltype(PFMeta<T>::from_cursor(*this)) as (int) const
{ return PFMeta<T>::from_cursor(*this); }
和一个通用的 as()
,收到一个 long
template <typename T>
T as (long) const // <-- accept a long; worst match
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
诀窍是未使用的参数:int
.
当启用专用 as()
时,如果首选因为接受 int
所以是更好的匹配。
当禁用专用 as()
时,保留通用 as()
作为 better-than-nothig 匹配。