编译时函数的选择取决于类型大小
compile-time function choice depending on type size
我想要一个模板函数来以特殊方式复制数据。如果数据元素类型大小是4字节的倍数。,(大小为(T(%4==0(:
template <typename T, typename Idx, uint32 dimensions>
void loadData4BWords(T *target, const T *source, const Idx eleCount);
如果不是这样的话,还有一种更复杂的方法来复制阵列:
template <typename T, typename Idx, uint32 dimensions>
void loadDataNo4BWords(T *target, const T *source, const Idx eleCount);
如何编写一个调用方模板函数,以便在编译时做出此决定并对用户透明?例如:
template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount);
它应该根据编译时条件multipleOf4BWord=(sizeof(T(%4==0(调用上面两个版本中的一个。更准确地说,loadData应该在编译时被翻译成上面两个版本中的一个。
您可以使用if constexpr
,因为C++17可以调用其中一个:
template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount) {
if constexpr(sizeof(T) % 4 == 0)
loadData4BWords<T, Idx, dimensions>(target, source, eleCount);
else
loadDataNo4BWords<T, Idx, dimensions>(target, source, eleCount);
}
与if
不同,if constexpr
在编译时进行测试,并且只编译匹配的分支。
if constexpr
是最好的。但老式的标签调度也有效,在某些情况下(尤其是在C++17之前(,它可能会更清晰,所以我将为讨论提供这个选项:
template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount, std::true_type)
{
loadData4BWords(target, source, eleCount);
}
template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount, std::false_type)
{
loadDataNo4BWords(target, source, eleCount);
}
template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount)
{
loadData(target, source, eleCount,
std::integral_constant<bool, sizeof(T) % 4 == 0>{});
}
您可以使函数成为结构的成员,并使用部分模板专用化:
template<typename T, bool is_even_multiple=0==(sizeof(T)%4)>
struct load_data_helper;
template<typename T>
struct load_data_helper<T, true>
{
template<uint32_t Dimensions, typename Idx>
static void apply(T * dest, T const * src, Idx const & index)
{ ... }
};
template<typename T>
struct load_data_helper<T, false>
{
template<uint32_t Dimensions, typename Idx>
static void apply(T * dest, T const * src, Idx const & index)
{ ... }
};
template<uint32_t Dimensions, typename T, typename Idx>
void load_data(T * dest, T const * src, Idx const & index)
{
load_data_helper<T>::apply<Dimensions>(dest, src, index);
}
然后呼叫将是:
load_data<3>(dest, src, index);
注意,我还没有真正编译过上面的代码,所以提供的代码中可能有错误,但概述的方法应该可以工作。
在C++17中,正如uneven_mark所建议的,if constexpr
是最简单、更清晰的解决方案(IMHO(。
在C++17(C++11和C++14(之前,您可以使用重载和SFINAE(带std::enable_if
(
我的意思是。。。如果不启用loadData4BWords()
和loadDataNo4BWords()
函数,而是创建仅在0u == sizeof(T) % 4u
(等效loadData4BWords()
(时启用的loadData()
和仅在0u != sizeof(T) % 4u
(等效loadDataNo4BWords()
(时启用loadData()
,则可以大大简化问题。
以下是完整的C++11工作示例(简化:只有一个参数(
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<0u == sizeof(T) % 4u>::type loadData (T *)
{ std::cout << "4 version" << std::endl; }
template <typename T>
typename std::enable_if<0u != sizeof(T) % 4u>::type loadData (T *)
{ std::cout << "no 4 version" << std::endl; }
int main ()
{
char ch;
int i;
loadData(&ch);
loadData(&i);
}
在C++14(如果你愿意,还可以使用C++17(中,你可以使用std::enable_if_t
来简化一点
template <typename T>
std::enable_if_t<0u == sizeof(T) % 4u> loadData (T *)
{ std::cout << "4 version" << std::endl; }
template <typename T>
std::enable_if_t<0u != sizeof(T) % 4u> loadData (T *)
{ std::cout << "no 4 version" << std::endl; }
附言:另请参阅Jeff Garrett的回答中的标签调度方式。
- SFINAE是否取决于类型推断?
- 将强制转换简化为取决于参数的类型
- cpp 模板专用化,错误说参数 1 的类型为 T,这取决于参数 T
- 编译时函数的选择取决于类型大小
- memcpy是否取决于源指针和目标指针的类型
- 如果条件取决于模板类型并且在编译时已知,是否可以保证C++编译器不会生成分支?
- 执行特定函数取决于类型
- 模板函数,其中模板参数类型取决于函数参数
- clang 拒绝具有尾随 decltype 返回类型的模板调用是否正确,具体取决于其重载之一?
- 基类数据成员类型取决于派生类
- 类型取决于模板中的条件
- 如何在基本模板类中声明成员,其中类型取决于派生类的类型
- 如何将函数指针声明指向模板函数,其返回类型取决于模板类
- 返回类型取决于模板参数
- 模板化结构的友元函数,其参数类型取决于结构的内部
- 变量模板函数,其中返回类型取决于模板参数列表
- C++ 模板返回类型取决于模板参数
- 返回类型取决于静态参数包字段
- 模板类的不同返回类型取决于类的形参
- 返回类型取决于算术运算的顺序.对吗?