簡體   English   中英

C ++模板MetaProgramming:在模板類型上編譯時間條件運算符

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

我正在使用模板元編程來創建Variant和Functor(通用仿函數)數據類型。 我有一個有趣的問題,需要以某種方式處理特定參數類型的參數。 理想情況下,如果條件滿足,我想使用某種編譯時條件運算符來處理方法A的給定參數,如果條件失敗則使用B.

高級問題摘要

  • 我需要通過variant的內部值將變量傳遞給函數指針,或者將變量本身傳遞給調用,具體取決於期望的參數類型是否為Variant類型。

細節

調用Functor時,使用Variants數組來模擬函數參數。 這是我的Functor的一個重載構造函數的示例:

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

可以使用我傳遞給它的任何類型的數據構造Variant。 這一切都很好,直到我得到這段代碼(這是一個特殊的函子調用助手類,用於需要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>( ) );
}

每個Functor都存儲一個函數指針,函數指針存儲在一個名為MultiFnPtr(多函數指針)的聯合中。 如上所示,當調用Functor時,聯合被強制轉換為適當的簽名類型。 傳遞給Functor的每個Variant都將通過GetValue方法轉換為Variant中保存的值。 這意味着我將在調用期間傳遞給Functor的每個Variants的內部數據轉換為它們各自的值。 要轉換為的值類型是從模板化的StaticFnCall與MultiFnPtr的簽名匹配推導出來的。

以下是GetValue的實現:

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

問題是我試圖在Functor中包含一個函數簽名,該函數簽名將Variant作為其參數類型之一。 只要調用Functor時,就可以將Variant傳遞給帶Variant的參數。 但是,我需要將任意類型傳遞給使用Variant的參數。 然后,GetValue將用於將任意類型轉換為Variant *,這會導致任意類型的數據按字面解釋為Variant,當我希望使用Variant的構造函數創建Variant以傳遞給被調用的函數指針時在Functor中。

我一直試圖想出一種方法直接將值傳遞給StaticFnCall的函數指針,而不是在相應的模板類型是Variant時使用GetValue。 我已經查找了std :: enable_if和sfinae,但我正在努力尋求一個解決方案。 這是我正在嘗試實現的偽代碼示例:

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>( ) );
}

編輯

所以我發現我可以使用模板化的全局函數並使用模板特化來以兩種方式之一處理參數。 但是,這不是編譯時解決方案,因為全局函數將導致分支,除非函數內聯。

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

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

由於函數ArgHandle在編譯時具有重載解析,我想可能有某種方法來實現我想要的行為而不需要函數調用。 采用:

#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 ) ) );
}

我不明白你為什么不在這部分問題之后停下來:

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

並為Variant添加模板特化:

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

並完成它。 有什么不適用於此? 好像你在后面的問題中繞過這個解決方案,但到那時你已經介紹了毫無意義的ArgHandle函數,宏和輔助函數,這只是一團糟。

就個人而言,我完全擺脫了GetValue函數,只提供隱式類型轉換運算符,因此你可以編寫fn(arg0, arg1, arg2) 但我想這取決於你的代碼的其余部分。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM