我希望能够使用不在我控制范围内的变量类中打包的参数调用任意函数(让我们称之为blackbox
)。我编写了一个函数模板unpack<T>
,它从blackbox
中提取需要专门用于目标类型的值。这适用于通过值传递的参数。但是,我不知道如何处理传递引用:
#include <string>
#include <functional>
#include <iostream>
#include <utility>
#include <type_traits>
/* Variant container */
struct blackbox
{
int int_value() const { return 42; }
bool bool_value() const { return true; }
std::string string_value() const { return "str"; }
};
/* Unpack function templates */
template<typename T>
T unpack(const blackbox &v)
{
static_assert(sizeof(T) == 0, "This template has to be specialized");
}
template<>
int unpack(const blackbox &v)
{
return v.int_value();
}
template<>
bool unpack(const blackbox &v)
{
return v.bool_value();
}
template<>
std::string unpack(const blackbox &v)
{
return v.string_value();
}
/* Call function with arguments extracted from blackbox */
template<typename T>
void call(std::function<void(T)> f, const blackbox &v)
{
f(unpack<T>(v));
}
/* Sample functions */
void f_int(int i) { std::cout << "f_int(" << i << ")" << std::endl; }
void f_bool(bool b) { std::cout << "f_bool(" << b << ")" << std::endl; }
void f_str(std::string s) { std::cout << "f_str(" << s << ")" << std::endl; }
void f_str_ref(const std::string &s) { std::cout << "f_str_ref(" << s << ")" << std::endl; }
int main()
{
blackbox b;
// direct call
f_str_ref(b.string_value());
// indirect call
call(std::function<void(int)>(f_int), b);
call(std::function<void(bool)>(f_bool), b);
call(std::function<void(std::string)>(f_str), b);
call(std::function<void(const std::string&)>(f_str_ref), b); //doesn't work
return 0;
}
我需要unpack
专门化,将std::string
个实例转发给带有const std::string&
参数的函数。定义
template<>
const std::string& unpack(const blackbox &v)
{
return v.string_value();
}
显然不起作用,因为返回了对局部变量的引用。不为unpack
定义const std::string&
特化会导致静态断言失败。
理想情况下,unpack<std::string>
应该用于const std::string&
,但提供单独的专业化就足够了。
答案 0 :(得分:1)
你需要std::decay<T>
来自<type_traits>
,删除 cv - 来自给定类型的参数和引用(除非这是函数或数组类型):
static_assert(std::is_same<std::decay<const std::string&>::type,
std::string>::value, "!");
话虽如此,您可以使用以下语法:
f(unpack<typename std::decay<T>::type>(v));
这样[cv / &
/ &&
] std::string
类型的任何变体都会评估为std::string
。