在可变参数模板上混合 const 和非常量变量
Mixing const and non-const variables on variadic template
我开发了一些通用的 reader 和 writer 包装函数(主要是为了避免在读取或写入文件的代码的每个部分上处理异常)。我的函数有这些签名:
写作:
/** 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
,反之亦然,reader 认为输入参数为 non-const
,因为我希望从 std::istream
.
写入它们
这很好用,但我已经到了这样的地步,我希望 reader 函数在其变量列表中具有 const
参数,或者编写器函数具有 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);
但这也不起作用:
/home/code/OutputWriter/src/entity_writer.cpp:46:122: error: no matching function for call to ‘writerFunctionWrapper(std::string&, void (*)(std::ofstream&, const ConstOutVar &, NonConstOutVar &), ConstOutVar &, NonConstOutVar &)’
Utils::writerFunctionWrapper(outFileName, writeSomeEntity, constOutVar, nonConstOutVar);
(注意错误如何显示 constOutVar & 而不是 constOutVar const &)
我注意到了[这个问题] (Variadic template trouble matching const and non-const std::string),但这并不是我在这里描述的情况。
有什么建议吗?
非常感谢。
Any suggestions?
就三个。
(1) 接受包装器中的函数作为通用模板类型,忽略接收到的参数的确切类型;这样你的包装器就非常灵活,因为它也可以接受一个 std::function
或一个 lambda(也是一个通用的 lambda)或(几乎相同)一个 struct/class 和一个 operator()
(也许是一个模板一)。这是不可能的,因为你只接受函数指针
(2) 接收参数作为通用引用转发引用并使用完美转发;完美转发正是为了解决您所面临的问题而设计的。
按照建议 (1) 和 (2),您需要一个包装器(为什么您需要一个 reader 和一个 writer 包装器,如果它们都只接受输入和 input/output 参数? ) 以下可能是一个简化的示例
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)...); }
这很重要,以避免您可以传递一个接收(通过示例)a std::string
的函数和一个 char const []
(字符串文字)的参数,从而在推导类型时出错.
我开发了一些通用的 reader 和 writer 包装函数(主要是为了避免在读取或写入文件的代码的每个部分上处理异常)。我的函数有这些签名:
写作:
/** 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
,反之亦然,reader 认为输入参数为 non-const
,因为我希望从 std::istream
.
这很好用,但我已经到了这样的地步,我希望 reader 函数在其变量列表中具有 const
参数,或者编写器函数具有 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);
但这也不起作用:
/home/code/OutputWriter/src/entity_writer.cpp:46:122: error: no matching function for call to ‘writerFunctionWrapper(std::string&, void (*)(std::ofstream&, const ConstOutVar &, NonConstOutVar &), ConstOutVar &, NonConstOutVar &)’
Utils::writerFunctionWrapper(outFileName, writeSomeEntity, constOutVar, nonConstOutVar);
(注意错误如何显示 constOutVar & 而不是 constOutVar const &)
我注意到了[这个问题] (Variadic template trouble matching const and non-const std::string),但这并不是我在这里描述的情况。
有什么建议吗?
非常感谢。
Any suggestions?
就三个。
(1) 接受包装器中的函数作为通用模板类型,忽略接收到的参数的确切类型;这样你的包装器就非常灵活,因为它也可以接受一个 std::function
或一个 lambda(也是一个通用的 lambda)或(几乎相同)一个 struct/class 和一个 operator()
(也许是一个模板一)。这是不可能的,因为你只接受函数指针
(2) 接收参数作为通用引用转发引用并使用完美转发;完美转发正是为了解决您所面临的问题而设计的。
按照建议 (1) 和 (2),您需要一个包装器(为什么您需要一个 reader 和一个 writer 包装器,如果它们都只接受输入和 input/output 参数? ) 以下可能是一个简化的示例
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)...); }
这很重要,以避免您可以传递一个接收(通过示例)a std::string
的函数和一个 char const []
(字符串文字)的参数,从而在推导类型时出错.