简体   繁体   English

C ++模板MetaProgramming:在模板类型上编译时间条件运算符

[英]C++ Template MetaProgramming: Compile Time Conditional Operator on Template Type

I'm using template metaprogramming to create a Variant and Functor (a generic functor) data type. 我正在使用模板元编程来创建Variant和Functor(通用仿函数)数据类型。 I have an interesting problem with needing to handle arguments a certain way for particular argument types. 我有一个有趣的问题,需要以某种方式处理特定参数类型的参数。 Ideally I'd like to use some sort of compile-time conditional operator to handle a given argument with method A if condition is met, and B if condition fails. 理想情况下,如果条件满足,我想使用某种编译时条件运算符来处理方法A的给定参数,如果条件失败则使用B.

High level problem summary : 高级问题摘要

  • I need to pass a variant to a call on a function pointer by either the variant's internal value, or pass the variant itself to the call depending on whether or not the argument type expected is of a Variant type. 我需要通过variant的内部值将变量传递给函数指针,或者将变量本身传递给调用,具体取决于期望的参数类型是否为Variant类型。

Details : 细节

When calling a Functor an array of Variants is used to simulate function arguments. 调用Functor时,使用Variants数组来模拟函数参数。 Here's an example of one of the overloaded constructors for my Functor : 这是我的Functor的一个重载构造函数的示例:

Variant operator()( Variant arg0, Variant arg1, Variant arg2 );

The Variant can be constructed with any type of data I pass to it. 可以使用我传递给它的任何类型的数据构造Variant。 This is all fine until I get to this piece of code (this is a specific functor call helper class for a signature requiring 3 arguments): 这一切都很好,直到我得到这段代码(这是一个特殊的函子调用助手类,用于需要3个参数的签名):

template <typename R, typename T0, typename T1, typename T2>
Variant StaticFnCall3( MultiFnPtr fn, Variant& arg0, Variant& arg1, Variant& arg2 )
{
  return reinterpret_cast<typename VoidToType<R>::type(*)(T0, T1, T2)>(fn.StaticFn)( arg0.GetValue<T0>( ), arg1.GetValue<T1>( ), arg2.GetValue<T2>( ) );
}

Each Functor stores a function pointer, and the function pointer is stored in a union called MultiFnPtr (multi function pointer). 每个Functor都存储一个函数指针,函数指针存储在一个名为MultiFnPtr(多函数指针)的联合中。 The union is typecasted to the appropriate signature type when the Functor is called, as seen above. 如上所示,当调用Functor时,联合被强制转换为适当的签名类型。 Each Variant passed to the Functor is converted to the value held within the Variant by the GetValue method. 传递给Functor的每个Variant都将通过GetValue方法转换为Variant中保存的值。 This means I'm converting each Variants' internal data that had been passed to the Functor during the call into their respective values. 这意味着我将在调用期间传递给Functor的每个Variants的内部数据转换为它们各自的值。 The value's type to convert to is deduced from matching a templated StaticFnCall to the MultiFnPtr's signature. 要转换为的值类型是从模板化的StaticFnCall与MultiFnPtr的签名匹配推导出来的。

Here is the implementation of GetValue: 以下是GetValue的实现:

template <typename TYPE>
const TYPE& VariantBase::GetValue( void ) const
{
  return *reinterpret_cast<TYPE *>(data);
}

The problem is that I'm trying to wrap a function signature within a Functor that takes a Variant as one of its parameter types. 问题是我试图在Functor中包含一个函数签名,该函数签名将Variant作为其参数类型之一。 This is fine as long as when the Functor is called a Variant is passed to the argument that takes a Variant. 只要调用Functor时,就可以将Variant传递给带Variant的参数。 However, I'm in need of passing an arbitrary type to the argument taking a Variant. 但是,我需要将任意类型传递给使用Variant的参数。 GetValue would then be used to convert an arbitrary type to a Variant *, which causes that arbitrary type's data to be interpreted as a Variant literally, when I desire to instead use the Variant's constructor to create a Variant to pass to the function pointer being called within the Functor. 然后,GetValue将用于将任意类型转换为Variant *,这会导致任意类型的数据按字面解释为Variant,当我希望使用Variant的构造函数创建Variant以传递给被调用的函数指针时在Functor中。

I've been trying to come up with a way of passing a value to the StaticFnCall's function pointer directly, instead of using GetValue when the corresponding template type is a Variant. 我一直试图想出一种方法直接将值传递给StaticFnCall的函数指针,而不是在相应的模板类型是Variant时使用GetValue。 I've looked up std::enable_if and sfinae but am struggling to get a solution together. 我已经查找了std :: enable_if和sfinae,但我正在努力寻求一个解决方案。 Here's an example in pseudo code of what I'm trying to achieve: 这是我正在尝试实现的伪代码示例:

template <typename R, typename T0, typename T1, typename T2>
Variant StaticFnCall3( MultiFnPtr fn, Variant& arg0, Variant& arg1, Variant& arg2 )
{
  return reinterpret_cast<typename VoidToType<R>::type(*)(T0, T1, T2)>(fn.StaticFn)( (IF_IS_VARIANT) ? arg0 : arg0.GetValue<T0>( ), (IF_IS_VARIANT) ? arg1 : arg1.GetValue<T1>( ), (IF_IS_VARIANT) ? arg2 : arg2.GetValue<T2>( ) );
}

EDIT : 编辑

So I figured out that I can use a templated global function and use template specialization to handle an argument in one of two ways. 所以我发现我可以使用模板化的全局函数并使用模板特化来以两种方式之一处理参数。 However this isn't a compile-time solution as a global function will cause branching, unless the function is inlined. 但是,这不是编译时解决方案,因为全局函数将导致分支,除非函数内联。

template<typename T>
const T ArgHandle( const RefVariant& arg )
{
  return arg.GetValue<T>( );
}

template<>
const Variant ArgHandle<Variant>( const RefVariant& arg )
{
  return Variant( arg );
}

Since the function ArgHandle has overload resolution at compile-time I imagine there might be some sort of way to achieve the behavior I'd like without a function call. 由于函数ArgHandle在编译时具有重载解析,我想可能有某种方法来实现我想要的行为而不需要函数调用。 Use: 采用:

#define ARG( NUM ) \
  ArgHandle<T##NUM>( arg##NUM )

template <typename R, typename T0, typename T1, typename T2>
Variant StaticFnCall3( MultiFnPtr fn, RefVariant& arg0, RefVariant& arg1, RefVariant& arg2 )
{
  return reinterpret_cast<typename VoidToType<R>::type(*)(T0, T1, T2)>(fn.StaticFn)( ARG( 0 ), ARG( 1 ), ARG( 2 ) ) );
}

I don't understand why you don't just stop after this part of your question: 我不明白你为什么不在这部分问题之后停下来:

template <typename TYPE>
const TYPE& VariantBase::GetValue( void ) const
{
  return *reinterpret_cast<TYPE *>(data);
}

and add a template specialization for Variant : 并为Variant添加模板特化:

template <>
const VariantBase& VariantBase::GetValue<VariantBase>( void ) const
{
  return *this;
}

and be done with it. 并完成它。 Does something not work with this? 有什么不适用于此? It seems like you were circling around to this solution later on in your question, but by then you'd introduced the pointless ArgHandle function, and macros, and helper functions, and it was just a mess. 好像你在后面的问题中绕过这个解决方案,但到那时你已经介绍了毫无意义的ArgHandle函数,宏和辅助函数,这只是一团糟。

Personally, I'd get rid of the GetValue function altogether, and just provide implicit type-conversion operators so you could write fn(arg0, arg1, arg2) . 就个人而言,我完全摆脱了GetValue函数,只提供隐式类型转换运算符,因此你可以编写fn(arg0, arg1, arg2) But I guess this depends on what the rest of your code looks like. 但我想这取决于你的代码的其余部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM