使用 boost mp11 有效地打开运行时值(处理功能完成时中断)
Using boost mp11 to switch on runtime value efficiently(breaking when processing function is done)
我有以下 code,我在其中实现调度运行时值以以某种方式解释数据(在这个玩具示例中,数据可以是 uint8_t 或短)。
代码似乎可以工作,但我想知道我是否可以以某种方式对代码进行微优化,以便在我命中(处理函数匹配)时停止处理(目前即使元组的第一个元素是整个“处理程序”元组在运行时迭代)。
#include <boost/mp11/tuple.hpp>
#include <iostream>
uint8_t data[4] = {0,1,100,2};
template<int runtimeId, typename T>
struct kindToType{
static constexpr int id = runtimeId;
using type = T;
};
const auto print =[]<typename T> (const T* data){
if constexpr(std::is_same_v<short, std::remove_cvref_t<T>>){
const short* values = (const short*)data;
std::cout << values[0] << " " << values[1] << std::endl;
} else if constexpr(std::is_same_v<uint8_t, std::remove_cvref_t<T>>){
const uint8_t* values = (const uint8_t*)data;
std::cout << (int)values[0] << " " << (int)values[1]<< " " << (int)values[2] << " " << (int)values[3] << std::endl;;
}
};
static constexpr std::tuple<kindToType<10, uint8_t>, kindToType<11, short>> mappings{};
void dispatch(int kind){
boost::mp11::tuple_for_each(mappings, [kind]<typename Mapping>(const Mapping&) {
if (Mapping::id == kind)
{
print((typename Mapping::type*)data);
}
});
}
int main()
{
// no guarantee that kind is index like(e.g. for two values
// it can have values 47 and 1701)
dispatch(10);
dispatch(11);
}
备注:
- 我可以not/want使用std::variant。
- 我不想使用 std::map 或 std::unordered 地图(其中值为
std::function
)
- 我知道这是过早的优化(假设处理程序完成大量工作,即使 10 次整数比较也很便宜)。
- 我的处理程序是独一无二的,即它是 std::map 之类的东西,而不是 std::multimap 之类的东西,所以
break;
. 没问题
- 不保证用于运行时值的 ID 种类在 [0,n-1] 中具有值。
- 只要在至少 1 个编译器中实现,我就可以接受 C++20 解决方案。
它的运行时性能在很大程度上取决于元组的大小。您可以制作自己的 for_each_tuple
实现,在您的函数执行时尽早执行:
template<typename FuncTuple, typename Selector>
void tuple_for_each(FuncTuple const& funcTuple, Selector selector)
{
std::apply([selector](auto const& ...funcs)
{
(void)(selector(funcs) || ...);
}, funcTuple);
}
您的发货将如下所示:
void dispatch(int kind)
{
tuple_for_each(mappings, [kind]<typename Mapping>(const Mapping&)
{
std::cout << "loop, ";
if (Mapping::id == kind)
{
print((typename Mapping::type*)data);
return true;
}
return false;
});
}
如果您去掉 lambda 中的模板并改用 auto
,此代码将使用 C++17 进行编译。我们使用运算符短路来发挥我们的优势,因此编译器将为我们提供一个早期输出。 Here 是完整代码。
此外,请注意演员 (const short*)data
是 UB。
我有以下 code,我在其中实现调度运行时值以以某种方式解释数据(在这个玩具示例中,数据可以是 uint8_t 或短)。
代码似乎可以工作,但我想知道我是否可以以某种方式对代码进行微优化,以便在我命中(处理函数匹配)时停止处理(目前即使元组的第一个元素是整个“处理程序”元组在运行时迭代)。
#include <boost/mp11/tuple.hpp>
#include <iostream>
uint8_t data[4] = {0,1,100,2};
template<int runtimeId, typename T>
struct kindToType{
static constexpr int id = runtimeId;
using type = T;
};
const auto print =[]<typename T> (const T* data){
if constexpr(std::is_same_v<short, std::remove_cvref_t<T>>){
const short* values = (const short*)data;
std::cout << values[0] << " " << values[1] << std::endl;
} else if constexpr(std::is_same_v<uint8_t, std::remove_cvref_t<T>>){
const uint8_t* values = (const uint8_t*)data;
std::cout << (int)values[0] << " " << (int)values[1]<< " " << (int)values[2] << " " << (int)values[3] << std::endl;;
}
};
static constexpr std::tuple<kindToType<10, uint8_t>, kindToType<11, short>> mappings{};
void dispatch(int kind){
boost::mp11::tuple_for_each(mappings, [kind]<typename Mapping>(const Mapping&) {
if (Mapping::id == kind)
{
print((typename Mapping::type*)data);
}
});
}
int main()
{
// no guarantee that kind is index like(e.g. for two values
// it can have values 47 and 1701)
dispatch(10);
dispatch(11);
}
备注:
- 我可以not/want使用std::variant。
- 我不想使用 std::map 或 std::unordered 地图(其中值为
std::function
) - 我知道这是过早的优化(假设处理程序完成大量工作,即使 10 次整数比较也很便宜)。
- 我的处理程序是独一无二的,即它是 std::map 之类的东西,而不是 std::multimap 之类的东西,所以
break;
. 没问题
- 不保证用于运行时值的 ID 种类在 [0,n-1] 中具有值。
- 只要在至少 1 个编译器中实现,我就可以接受 C++20 解决方案。
它的运行时性能在很大程度上取决于元组的大小。您可以制作自己的 for_each_tuple
实现,在您的函数执行时尽早执行:
template<typename FuncTuple, typename Selector>
void tuple_for_each(FuncTuple const& funcTuple, Selector selector)
{
std::apply([selector](auto const& ...funcs)
{
(void)(selector(funcs) || ...);
}, funcTuple);
}
您的发货将如下所示:
void dispatch(int kind)
{
tuple_for_each(mappings, [kind]<typename Mapping>(const Mapping&)
{
std::cout << "loop, ";
if (Mapping::id == kind)
{
print((typename Mapping::type*)data);
return true;
}
return false;
});
}
如果您去掉 lambda 中的模板并改用 auto
,此代码将使用 C++17 进行编译。我们使用运算符短路来发挥我们的优势,因此编译器将为我们提供一个早期输出。 Here 是完整代码。
此外,请注意演员 (const short*)data
是 UB。