Aja*_*jay 17 c++ visual-c++ c++11 c++14
有两个"C"功能:
void fooA(const char*);
void fooW(const wchar_t*);
Run Code Online (Sandbox Code Playgroud)
然后有一个包装模板函数:
template<typename _TChar>
void foo(const _TChar* str)
{
// call fooA or fooB based on actual type of _TChar
// std::conditional .. ?
// fooA(str);
// fooW(str);
}
Run Code Online (Sandbox Code Playgroud)
如果调用者调用foo("Abc"),则此模板函数应进行编译时调用fooA.同样,foo(L"Abc")应该做最后的调用fooW.
我怎么做?我想过使用std::conditional但不能成功.
我无法制作fooA或fooB过载,因为这些是C函数.
Naw*_*waz 14
你可以把所有的wchar_t版本类模板,说overloads他们char在其专门的反零件,如下图所示:
template<typename WideCharVersion>
struct overloads
{
void foo(wchar_t const * arg)
{
FooW(arg);
}
//more wchar_t functions
};
template<>
struct overloads<std::false_type>
{
void foo(char const * arg)
{
FooA(arg);
}
//more char functions
};
//a friendly alias!
template<typename T>
using is_wide_char = typename std::is_same<whar_t, T>::type;
Run Code Online (Sandbox Code Playgroud)
然后你可以使用它们:
template<typename _TChar>
void foo(const _TChar* str)
{
overloads<is_wide_char<_TChar>>::foo(str);
}
Run Code Online (Sandbox Code Playgroud)
其他方法是使用表达式SFINAE,它不需要你写任何类似的东西overloads,并用较少的代码完成相同的工作:
template<typename _TChar>
void foo(const _TChar* str)
{
invokeOne(fooA, fooW, str);
}
Run Code Online (Sandbox Code Playgroud)
然后你可以实现invokeOne:
template<typename F1, typename F2, typename ... Args>
auto invokeOne(F1 f1, F2 f2, Args && ... args) -> decltype(f1(args...))
{
return f1(args...);
}
template<typename F1, typename F2, typename ... Args>
auto invokeOne(F1 f1, F2 f2, Args && ... args) -> decltype(f2(args...))
{
return f2(args...);
}
Run Code Online (Sandbox Code Playgroud)
看看在线演示.
在这种方法中,你不必重载添加到overloads类模板和它的专业化.相反,你只需将它们作为参数传递给你invokeOne,为你调用正确的重载.
希望有所帮助.
然后重载另一个函数.我假设foo做了更多的工作,需要成为一个模板.然后调用foo_forward_call,定义如下:
void foo_forward_call(char const* ptr) {
FooA(ptr);
}
void foo_forward_call(wchar_t const* ptr) {
FooW(ptr);
}
Run Code Online (Sandbox Code Playgroud)
并在通话现场:
template<typename _TChar>
void foo(const _TChar* str)
{
foo_forward_call(str);
}
Run Code Online (Sandbox Code Playgroud)
在C++ 1z中你将能够使用constexpr if,但说实话,我认为重载的解决方案仍然更具可读性.
template<typename _TChar>
void foo(const _TChar* str)
{
if constexpr(std::is_same<_TChar, char>::value) {
FooA(str);
} else {
FooW(str);
}
}
Run Code Online (Sandbox Code Playgroud)
或者,你可以使用Boost.Hana的overload:
template<typename _TChar>
void foo(const _TChar* str)
{
hana::overload(fooA, fooW)(str);
}
Run Code Online (Sandbox Code Playgroud)
顺便说一下:你应该避免在你的程序中使用下划线 - 大写字母名称.它们保留用于任何用途(即宏)的实现,并可能导致令人讨厌的名称冲突.
这对模板来说似乎很奇怪.我建议使用正常的重载:
void foo(const char* p) { fooA(p); }
void foo(const wchar_t* p) { fooW(p); }
Run Code Online (Sandbox Code Playgroud)
如果你坚持使用模板,那么你可以这样做:
template <typename T>
void foo(const T* p)
{
// Declare functions here so that calling fooW with const char*
// and 'calling' fooA with const wchar_t* would not cause compile error.
void fooA(const T*);
void fooW(const T*);
if (std::is_same<char, T>::value)
fooA(p);
else
fooW(p);
}
Run Code Online (Sandbox Code Playgroud)
我喜欢一般解决问题.所以让我们设计一种机制来重载东西.
overload_t<...>获取一组callables ...并生成一个对象,该对象使用标准的重载决策来在它们之间进行选择,通过继承operator():
template<class...Fs>
struct overload_t;
// the case where we have a function object:
template<class F>
struct overload_t<F>:F{
overload_t(F f):F(std::move(f)){}
using F::operator();
// boilerplate to ensure these are enabled if possible:
overload_t(overload_t&&)=default;
overload_t(overload_t const&)=default;
overload_t& operator=(overload_t&&)=default;
overload_t& operator=(overload_t const&)=default;
};
// we cannot inherit from a function pointer. So
// store one, and write an `operator()` that forwards to it:
template<class R, class...Args>
struct overload_t<R(*)(Args...)>{
using F=R(*)(Args...);
F f;
overload_t(F fin):f(fin){}
R operator()(Args...args)const{
return f(std::forward<Args>(args)...);
}
overload_t(overload_t&&)=default;
overload_t(overload_t const&)=default;
overload_t& operator=(overload_t&&)=default;
overload_t& operator=(overload_t const&)=default;
};
// the case where we have more than type to overload.
// recursively inherit from the one-arg and the rest-of-arg
// and using operator() to bring both of their () into equal standing:
template<class F0, class...Fs>
struct overload_t<F0,Fs...>:
overload_t<F0>,
overload_t<Fs...>
{
using overload_t<F0>::operator();
using overload_t<Fs...>::operator();
overload_t(F0 f0, Fs...fs):
overload_t<F0>(std::move(f0)),
overload_t<Fs...>(std::move(fs)...)
{}
overload_t(overload_t&&)=default;
overload_t(overload_t const&)=default;
overload_t& operator=(overload_t&&)=default;
overload_t& operator=(overload_t const&)=default;
};
// a helper function to create an overload set without
// having to specify types. Will be obsolete in C++17:
template<class...Fs>
overload_t<Fs...> overload(Fs...fs){ return {std::move(fs)...};}
Run Code Online (Sandbox Code Playgroud)
现在要生成一个多重载荷的单个对象,请执行以下操作:
overload(FooA,FooW)( str );
Run Code Online (Sandbox Code Playgroud)
并将str根据通常的重载决策规则调度.这在其他地方很有用,这就是为什么值得写,并且使用时的代码是自我记录.
实例(哇,第一次写错了!)
可以在上面添加许多改进overload_t.
f在施工期间和辅助功能中完美转发s.
平衡的二叉树继承而不是线性(重要的是超过几个重载完成).这可能具有运行时和编译时性能隐含,特别是对于大量函数.
反思来袭Fs; 如果他们overload_t平衡了组合树.
在C++ 17中,一个func<auto>模板,它接受一个函数指针并返回一个无状态调用它的函数对象.编译器相对擅长于删除函数指针,但是当没有可能改变它们的可能的运行时状态时,它们会更好.
决定做什么overload_t<>.目前无法编译; 也许它应该只是一个空的struct {},甚至是一个不可赎回的结构operator().
检查现有的库,比如boost::hana::overload看看它们有什么不同.
公开提取哪些重载将被调用的能力,可能通过一种static tag_t<F> which_overload_helper( Args... ) const方法和template<class...Args> using which_overload = typename decltype( which_overload_helper( std::declval<Args>()... ) )::type;
当一些传入的Fss /没有时,正确地选择重载const operator().如果函数指针有const,volatile,或两者都不对operator()?全部4个?如何&&VS &超载?
| 归档时间: |
|
| 查看次数: |
5438 次 |
| 最近记录: |