在可变参数模板上混合const和非const变量

时间:2019-07-18 19:47:40

标签: c++ variadic-templates template-deduction

我已经开发了几个通用的读取器和写入器包装器函数(主要是为了避免必须处理读取或写入文件的代码各部分的异常)。我的函数具有以下签名:

写作:

/** 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),但这并不是我在此描述的情况。

有什么建议吗?

非常感谢高级

1 个答案:

答案 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>