如果传递函数指针或函数,我想让辅助函数或模板化结构做不同的事情,但如果我正确理解模板系统,这是不可能的,因为一个是类型而另一个是不
我是否正确?如果可能的话,我希望保持我的API相同,将其传递给函子或函数指针,但如果不需要则不会产生存储指针的成本。 E.g:
template <typename T, void(*fn)(T)>
struct X1
{
T m_t;
X(T t) : m_t(t) {}
void invoke() { fn(m_t); }
};
template <typename T, typename F>
struct X2
{
T m_t;
F m_f;
X(T t, F f) : m_t(t), m_f(f) {}
void invoke() { m_f(m_t); }
};
因此,在这种情况下,我要么让这些结构共享相同的名称,要么让辅助函数使用函数或函数指针实例化相应的结构,这些函数指针放在相同的参数位置并具有相同的装饰在函数/函子周围。
类似的东西:
void fn(int) {}
auto functor = [](int){};
int h = 3;
auto x1 = make_X(h, fn);
auto x2 = make_X(h, functor);
make_X()
是我正在寻找的链接。想法?
答案 0 :(得分:2)
单一责任原则说,围绕函数指针的优化是无状态的,其余的代码应该单独处理。
因此,创建一个无状态函子,在代码的一部分中调用fn
:
template<class Sig, Sig* fn>
auto stateless() {
return [](auto&&...args)->decltype(auto){
return fn(decltype(args)(args)...);
};
}
这是C ++ 14。在C ++ 11中,您只需手动编写该lambda的等效项。 1
空基优化帮助器使存储类型的空实例变得便宜且容易:
template<class Tag, class T, class=void>
struct ebo {
ebo( T tin ):t(std::forward<T>(tin)) {}
T t;
T& get( Tag ){ return t; }
T const& get( Tag ) const { return t; }
ebo(ebo&&)=default;
ebo(ebo const&)=default;
ebo&operator=(ebo&&)=default;
ebo&operator=(ebo const&)=default;
ebo()=default;
};
template<class Tag, class T>
struct ebo<Tag, T,
std::enable_if_t<std::is_empty<T>{} && !std::is_final<T>{}>
>:
T
{
ebo( T tin ):T(std::forward<T>(tin)) {}
T& get( Tag ){ return *this; }
T const& get( Tag ) const { return *this; }
ebo(ebo&&)=default;
ebo(ebo const&)=default;
ebo&operator=(ebo&&)=default;
ebo&operator=(ebo const&)=default;
ebo()=default;
};
使用以上内容实施X
:
struct F_tag {};
template <typename T, typename F>
struct X:ebo<F_tag, F>
{
X(T tin, F fin):
ebo<F_tag,F>(std::forward<F>(fin)),
m_t(std::forward<T>(tin))
{}
T m_t;
void invoke() { this->get(F_tag{})(m_t); }
};
template<class T, class F>
X<T,F> make_X( T t, F f ) {
return {std::forward<T>(t),std::forward<F>(f)};
}
在使用时,这看起来像:
void fn(int) {}
auto functor = [](int){};
int h = 3;
auto x1 = make_X(h, stateless<void(int),&fn>());
auto x2 = make_X(h, functor);
零字节用于存储fn(int)
或functor
。
我按值计算:添加转发参考作为练习。
1 C ++ 11版stateless
:
template<class Sig, Sig* fn>
struct stateless_t {
template<class...Ts>
auto operator()(Ts&&...ts)const
-> decltype( fn(std::declval<Ts>()...) )
{ return fn(std::forward<Ts>(ts)...); }
};
template<class Sig, Sig* fn>
stateless_t<Sig, fn> stateless() { return {}; }