我希望做这样的事情:
void func(void *data, const int dtype)
{
typedef typename std::conditional<dtype==0,float,double>::type DataType;
funcT((DataType *)data);
return;
}
这不会编译,因为dtype需要在编译时知道。我试图避免使用switch语句,因为我正在使用8种数据类型,有许多函数,例如上面的函数,通过ctypes从Python调用。
有没有像std :: conditional这样的方法可以在运行时完成,利用传入的dtype标识符?
答案 0 :(得分:5)
必须在编译时解析所有类型。因此,没有类型可以依赖于函数的运行时参数。处理这样的事情的方法基本上是建立一个访问机制,然后你可以重用它。基本上,这样的事情:
array_reverse
现在,您可以通过撰写访问者来实现功能:
template <class F>
void visit_data(void* data, const int dtype, F f) {
switch (dtype)
case 0: f(*static_cast<float*>(data));
case 1: f(*static_cast<double*>(data));
}
您的访问者也可以使用通用代码:
struct func_impl {
void operator()(float&) { ... }
void operator()(double&) { ... }
};
然后你可以通过利用访客来编写你的功能:
struct func_impl2 {
template <class T>
void operator()(T&) { ... }
};
类型列表中的切换案例只会在整个代码库中出现一次。如果添加新类型,任何不处理它的访问者在使用时都会产生编译时错误。
你也可以使用lambdas与一个或两个辅助函数内联;特别适用于你有普通lambda的地方。
答案 1 :(得分:4)
如果您可以使用C ++ 17,可以使用std::visitor
和std::variant
来解决,例如:
using var_t = std::variant<float, double>;
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
void func(var_t arg) {
std::visit(overloaded {
[](float arg) { foo_float(arg); },
[](double arg) { foo_double(arg); },
}, arg);
}
答案 2 :(得分:3)
假设您有一个类型列表:
template<std::size_t I, class...Ts>
using get_type = std::decay_t<decltype(std::get<I>(std::declval<std::tuple<Ts...>&>()))>;
template<std::size_t I, class Types>
struct type_at_helper;
template<std::size_t I, class...Ts>
struct type_at_helper<I, types<Ts...>>{
using type=get_type<I,Ts...>;
};
template<std::size_t I, class Types>
using type_at = typename type_at_helper<I,Types>::type;
接下来我们编写一些实用函数
type_at<2, decltype(supperted_types)>
现在,char
为namespace helper {
template<class F>
using invoker = void(*)(F&&, void*);
template<class F, class Types, std::size_t I>
invoker<F> get_invoker() {
return [](F&& f, void* pdata) {
std::forward<F>(f)( static_cast<type_at<I, Types>*>(pdata) );
};
}
template<class F, class Types, std::size_t...Is>
void dispatch( F&& f, void* data, unsigned type_index, std::index_sequence<Is...>, Types ={} ) {
using pF=std::decay_t<F>*;
using invoker = void(*)(pF, void*);
static const invoker table[]={
get_invoker<F, Types, Is>()...
};
table[type_index]( std::forward<F>(f), data );
}
}
template<class F, class...Ts>
void dispatch( F&& f, void* data, unsigned type_index, types<Ts...> {} ) {
details::dispatch( std::forward<F>(f), data, type_index, std::make_index_sequence<sizeof...(Ts)>{}, types<Ts...>{} );
}
。
make_index_sequence
并完成。
降级为c++11只需撰写index_sequence
和action="<?php echo $_SERVER['PHP_SELF']; ?>"
即可。 Here is a high quality one,但有更容易的。
答案 3 :(得分:2)
有没有像
std::conditional
这样的方法可以在运行时完成,使用传入的dtype
标识符?
不,没有。运行时值不能用于在编译类型中进行基于类型的决策。
鉴于您的帖子,最简单的解决方案是使用if
语句。
void func(void *data, const int dtype)
{
if ( dtype == 0 )
{
funcT(static_cast<float*>(data));
}
else
{
funcT(static_cast<double*>(data));
}
}
为了能够处理大量此类功能,我建议使用std::map<int, std::function<void(void*)>>
。
这是一个为我编译和构建的简单程序。
#include <map>
#include <functional>
void funcT(float* data)
{
}
void funcT(double* data)
{
}
struct MyType {};
void funcT(MyType* data)
{
}
void func(void *data, const int dtype)
{
std::map<int, std::function<void(void*)>> functions =
{
{0, [](void* in) {funcT(static_cast<float*>(in));}},
{1, [](void* in) {funcT(static_cast<double*>(in));}},
// ...
{7, [](void* in) {funcT(static_cast<MyType*>(in));}}
};
if ( functions[dtype] != nullptr )
{
functions[dtype](data);
}
}
int main(){}
使用lambda函数的一个优点是,您可以自由地为各种类型调用不同命名的函数。例如,您可以选择使用:
void foo(MyType* data) {}
和
{7, [](void* in) {foo(static_cast<MyType*>(in));}}
答案 4 :(得分:0)
我对该问题的解决方案是一个通用selectFunc()
函数,该函数将根据FS
从提供的函数集dtype
中选择一个函数,并将其返回:
using FuncType = void(*)(void*);
template<typename FS>
FuncType selectFunc(int dtype);
函数集将是一个具有静态handle()
方法的类,它接受不同类型和静态fallback()
方法,如果dtype
无效,则会调用该方法。
使用示例:
struct FuncSet
{
static void fallback() {};
static void handle(float*) {};
static void handle(double*) {};
};
void func(void *data, int dtype)
{
// select a function from FuncSet based on dtype:
auto f = selectFunc<FuncSet>(dtype);
// invoke the selected function with the provided data:
f(data);
// note, two lines above could be combined into one line
}
<强>实施强>
// Static method which would call the correct FS::handle() method
template<typename FS, typename T>
struct Helper
{
static void dispatch(void *data) { FS::handle(static_cast<T*>(data)); }
};
// Static method which would call FS::fallback()
template<typename FS>
struct Helper<FS, void>
{
static void dispatch(void*) { FS::fallback(); }
};
template<typename FS>
FuncType selectFunc(int dtype)
{
switch ( dtype ) {
case 0: return &Helper<FS, float>::dispatch;
case 1: return &Helper<FS, double>::dispatch;
// ... add other types here ...
default: return &Helper<FS, void>::dispatch; // call fallback()
}
}