C++ 基于模板参数类型的调用函数
有两个“C”功能:C++ 基于模板参数类型的调用函数,c++,c++11,visual-c++,c++14,C++,C++11,Visual C++,C++14,有两个“C”功能: void fooA(const char*); void fooW(const wchar_t*); 还有一个包装器模板函数: template<typename _TChar> void foo(const _TChar* str) { // call fooA or fooB based on actual type of _TChar // std::conditional .. ? // fooA(str);
void fooA(const char*);
void fooW(const wchar_t*);
还有一个包装器模板函数:
template<typename _TChar>
void foo(const _TChar* str)
{
// call fooA or fooB based on actual type of _TChar
// std::conditional .. ?
// fooA(str);
// fooW(str);
}
void helper(const char* x) { FooA(x); }
void helper(const wchar_t* x) { FooW(x); }
template <typename _TChar>
void foo(const _TChar* str)
{
helper(str);
}
模板
void foo(const_TChar*str)
{
//根据实际的\u TChar类型调用fooA或fooB
//std::条件?
//fooA(str);
//fooW(str);
}
如果调用方调用foo(“Abc”)
,则此模板函数应在编译时调用fooA
。类似地,foo(L“Abc”)
应该最后调用fooW
我该怎么做?我曾想过使用std::conditional,但没有成功
我不能使
fooA
或fooB
重载,因为它们是C函数。您可以将所有您的wchar\t
版本放在类模板中,比如重载及其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;
然后您可以实现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...);
}
模板
自动调用一个(F1、F2、参数和…参数)->decltype(F1(参数…)
{
返回f1(args…);
}
模板
自动调用One(F1、F2、F2、Args&…Args)->decltype(F2(Args…)
{
返回f2(args…);
}
看一看这张照片
在这种方法中,您不必将重载添加到重载
类模板中,也不必将重载添加到其专门化中。相反,您只需将它们作为参数传递给invokeOne
,后者为您调用正确的重载
希望有帮助。然后重载另一个函数。我假设foo
做了更多的工作,需要成为一个模板。然后调用foo\u forward\u call
,定义如下:
void foo_forward_call(char const* ptr) {
FooA(ptr);
}
void foo_forward_call(wchar_t const* ptr) {
FooW(ptr);
}
在呼叫站点:
template<typename _TChar>
void foo(const _TChar* str)
{
foo_forward_call(str);
}
或者,您可以使用Boost.Hana
:
模板
void foo(const_TChar*str)
{
hana::过载(fooA,fooW)(str);
}
顺便说一下:您应该避免在程序中使用下划线大写字母名称。它们保留用于实现任何用途(即宏),可能会导致严重的名称冲突。您有一些选择
使用显式专用的辅助对象结构
:
template <typename>
struct helper;
template<>
struct helper<char>
{
void operator()(const char* x){ FooA(x); }
};
template<>
struct helper<wchar_t>
{
void operator()(const wchar_t* x){ FooW(x); }
};
template <typename _TChar>
void foo(const _TChar* str)
{
helper<_TChar>{}(str);
}
模板
结构助手;
模板
结构辅助程序
{
void运算符()(const char*x){FooA(x);}
};
模板
结构辅助程序
{
void运算符()(常量wchar_t*x){FooW(x);}
};
模板
void foo(const_TChar*str)
{
助手{}(str);
}
使用“静态if”实现(例如或):
模板
void foo(const_TChar*str)
{
vrm::core::static_if(std::is_same{})
。然后([](const auto*x_str){FooA(x_str);})
.else(const auto*x_str){FooW(x_str);})(str);
}
使用帮助器重载函数:
template<typename _TChar>
void foo(const _TChar* str)
{
// call fooA or fooB based on actual type of _TChar
// std::conditional .. ?
// fooA(str);
// fooW(str);
}
void helper(const char* x) { FooA(x); }
void helper(const wchar_t* x) { FooW(x); }
template <typename _TChar>
void foo(const _TChar* str)
{
helper(str);
}
void helper(const char*x){FooA(x);}
void helper(const wchar_t*x){FooW(x);}
模板
void foo(const_TChar*str)
{
助手(str);
}
对于模板来说,这似乎是一件非常奇怪的事情。我建议改用普通重载:
void foo(const char* p) { fooA(p); }
void foo(const wchar_t* p) { fooW(p); }
如果您坚持使用模板,则可以这样做:
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);
}
模板
无效foo(常数T*p)
{
//在此声明函数,以便使用const char调用fooW*
//使用const wchar\u t*调用fooA不会导致编译错误。
无效fooA(常数T*);
void fooW(const T*);
if(std::is_same::value)
食品添加剂(p);
其他的
fooW(p);
}
如果有更多的目标函数,或者重载不是您试图解决的唯一问题,那么使用模板来完成这项工作可能是值得的
但在这种情况下,只需编写您的重载:
void foo(const char* x) { fooA(x); }
void foo(const wchar_t* x) { fooW(x); }
我一般喜欢解决问题。因此,让我们设计一种机制来过载
重载\u t
通过继承操作符()
,在..
中获取一组可调用项,并生成一个使用标准重载分辨率在它们之间进行选择的对象:
根据通常的重载解决规则,str
将被分派到其中一个。这在其他地方很有用,这就是为什么它值得编写的原因,并且使用的代码是自文档化的
(哇,第一次写对了!)
有许多改进可以添加到上面的重载\u t
- 在构建过程中和助手函数中完美地转发
f
s
- 平衡的二叉树继承而不是线性继承(重要的是要完成多个重载)。这可能会影响运行时和编译时性能,特别是对于大量函数
- 内省传入的
Fs
;如果它们过载,则平衡组合树
- 在C++17中,一种
func
模板,它接受函数指针并返回一个无状态调用它的函数对象。编译器在省略函数指针方面相对较好,但在没有可能改变函数指针的运行时状态时,编译器在这方面做得更好
- 决定如何处理
过载\u t
。目前没有编译,;也许它应该是一个空的结构{}
,或者甚至是一个带有不可调用的操作符()的结构
- 检查现有的库,比如
boost::hana::重载
,看看有什么不同
- 公开提取哪些重载将被调用的能力,可能通过
静态标记\u t which\u-overload\u-helper(Args…)const
方法和使用which\u-overload=typename decltype的模板(which\u-overload\u-helper(std::declval())::type代码>
- 当一些传入的
Fs
s没有/没有const
操作符()
时,正确选择重载。函数指针是否在操作符()上同时具有常量
、易失性
?全部4个?&&
void foo(const char* p) { fooA(p); }
void foo(const wchar_t* p) { fooW(p); }
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);
}
void foo(const char* x) { fooA(x); }
void foo(const wchar_t* x) { fooW(x); }
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)...};}
overload(FooA,FooW)( str );