我已经开发了几个通用的读取器和写入器包装器函数(主要是为了避免必须处理读取或写入文件的代码各部分的异常)。我的函数具有以下签名:
写作:
/** Generic writer function alias for free functions */
template<typename ... Args>
using WriterFunction = void (*)(std::ofstream &, Args const & ... args);
/**
* \brief Wrapper used to encapsulate a generic free function writing to an output stream
* \param[in] outFileName Name of the output file to be written.
* \param[in] writeFunction Function used to export the data.
* \param[in] ... Variable number of arguments to be passed to the previous function.
*/
template<typename ... Args>
void writerFunctionWrapper(
std::string const &outFileName,
WriterFunction<Args ...> writeFunction,
Args const & ... args);
阅读:
/** Generic reader function alias for free functions */
template<typename ... Args>
using ReaderFunction = void (*)(std::ifstream &, Args & ... args);
/**
* \brief Wrapper used to encapsulate a generic free function reading from an input stream
* \param[in] inFileName Name of the input file to be read.
* \param[in] readFunction Function used to import the data.
* \param[in] ... Variable number of arguments to be passed to the previous function.
*/
template<typename ... Args>
void readerFunctionWrapper(
std::string const &inFileName,
ReaderFunction<Args ...> readFunction,
Args & ... args);
因此,主要区别在于作者将输入参数视为const
,正如我希望将它们从std::ostream
中读取一样,而反之,读者将输入参数视为{{ 1}},正如我期望从non-const
写给他们的信。
这很好用,但我想说的是,我想在其变量列表中使用带有std::istream
参数的阅读器函数,或也带有const
参数的writer函数。但是,当参数列表可变时,我不知道该怎么办。
我尝试将别名和模板修改为
non-const
template<typename ... ArgsConst, typename ... ArgsNonConst>
using WriterFunction = void (*)(std::ofstream &, ArgsConst const & ... argsConst, ArgsNonConst & ... argsNonConst);
具有在参数template<
typename ... ArgsConst,
typename ... ArgsNonConst>
void writerFunctionWrapper(
std::string const &outFileName,
WriterFunction<ArgsConst ..., ArgsNonConst ...> writeFunction,
ArgsConst const & ... argsConst,
ArgsNonConst & ... argsNonConst);
中放置顺序的缺点,首先是writeFunction()
,然后是非const
,但这是一个较小的邪恶。但是,这对我不起作用:
const
我还尝试通过将别名和模板扩展为以下方式来简单地混合使用/home/code/Utils/include/file_utils.h:42:11: error: parameter pack ‘ArgsConst’ must be at the end of the template parameter list
template<typename ... ArgsConst, typename ... ArgsNonConst>
和非const
参数:
const
/** Generic writer function alias for free functions */
template<typename ... Args>
using WriterFunctionGeneral = void (*)(std::ofstream &, Args const & ... argsConst, Args & ... argsNonConst);
但是当我尝试在将template<typename ... Args>
void writerFunctionWrapper(
std::string const &outFileName,
WriterFunctionGeneral<Args ...> writeFunctionGeneral,
Args const & ... argsConst,
Args & ... argsNonConst);
和非const
参数混合使用的函数上使用它时,这种方法都不起作用,例如:
const
并以以下方式调用它:
void writeSomeEntity(
std::ofstream &outWriter,
ConstOutVar const &constVar,
NonConstOutVar &nonConstVar);
但是那也不起作用:
ConstOutVar constVar;
NonConstOutVar nonConstVar;
...
Utils::writerFunctionWrapper(outFileName, &writeSomeEntity, constVar, nonConstVar);
(请注意该错误如何显示 constOutVar和,而不是 constOutVar const&)
我注意到了[这个问题](Variadic template trouble matching const and non-const std::string),但这并不是我在此描述的情况。
有什么建议吗?
非常感谢高级
。答案 0 :(得分:2)
有什么建议吗?
就三个。
(1)接受包装器中的函数作为通用模板类型,而忽略接收到的参数的确切类型;这样,您的包装器就非常灵活,因为它也可以接受std::function
或lambda(也可以是通用lambda)或(几乎相同)带有operator()
的struct / class(可能是模板) 。这是不可能的,因为您仅接受函数指针
(2)接收参数作为通用引用转发引用,并使用完美转发;完美的转发功能旨在解决您面临的问题。
根据建议(1)和(2),您需要一个包装器(如果它们都只接受输入和输入/输出参数,为什么需要阅读器和写入器包装器?),以下内容可以简化例子
template <typename F, typename ... Args>
void FunctionWrapper(F && f, Args && ... args)
{ std::forward<F>(f)(std::forward<Args>(args)...); }
但是,如果您真的(真的!)想要一个或多个包装器仅接受传统函数指针,则可以提出建议(3)
(3)使用两个可变参数的模板类型集作为参数;一组用于函数指针,另一组用于参数;我的意思是……如下
template <typename ... FAs, typename ... As>
void FunctionWrapperPnt (void(*f)(FAs...), As && ... as)
{ f(std::forward<As>(as)...); }
这一点很重要,以避免您可以传递一个接收(例如)std::string
和一个参数char const []
(字符串文字)的参数,该函数在推导类型时产生错误。 / p>