问题描述
我有一个模板类,必须在调用参数和返回类型通用的函数之前执行一些操作.
I have a template class that must perform some operation before calling a function whose parameters and return type are generic.
这是方法:
template <typename ReturnType, typename ...Args>
ReturnType function (Args ...args) {
// prepare for call
// ...
ReturnType rv = makeCall(args...); // [1]
// dismiss the call
// ...
return rv;
}
当然,当 ReturnType
不是 void
时,它可以正确编译.当我在这种情况下使用它时:
Of course it's compiling correctly when ReturnType
is not void
.When I use it in this context:
function<void>(firstArg, secondArg);
编译器以
错误:函数返回"void" [-fpermissive]
指向标有[1]的行.
除了将 -fpermissive
传递给编译器之外,还有其他解决方案吗?我希望有一个独特的方法,因为我发现的可能解决方案是使用 enable_if
和 is_same
实例化不同的版本.
Is there any solution other than passing -fpermissive
to the compiler?I would prefer to have a unique method, because I possible solution I found is to instantiate different versions using enable_if
and is_same
.
谢谢.
-更新-
这是一个完整的示例.我应该说我们的函数确实是类方法.
This is a complete example. I should have said that our functions are indeed class methods.
#include <type_traits>
#include <iostream>
class Caller {
public:
Caller() {}
template <typename ReturnType, typename ...Arguments>
ReturnType call(Arguments ... args) {
prepare();
ReturnType rv = callImpl<ReturnType>(args...);
done();
return rv;
}
private:
void prepare() {
std::cout << "Prepare\n";
}
void done() {
std::cout << "Done\n";
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, void>::value, ReturnType>::type callImpl ( Arguments ... args) {
std::cout << "Calling with void\n";
return;
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, bool>::value, ReturnType>::type callImpl (Arguments ... args) {
std::cout << "Calling with bool\n";
return true;
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, int>::value, ReturnType>::type callImpl (Arguments ... args) {
std::cout << "Calling with int\n";
return 42;
}
};
int main(int argc, char *argv[]) {
Caller c;
auto rbool = c.call<bool> (1,20);
std::cout << "Return: " << rbool << "\n";
auto rint = c.call<int> (1,20);
std::cout << "Return: " << rint << "\n";
// the next line fails compilation. compile with --std=c++11
c.call<void>("abababa");
return 0;
}
-更新-
没什么大问题:使用 std :: bind(& Caller :: callImpl< ReturnType> ;,这个,args)
.
推荐答案
这是我尝试的一种通用的C ++ 11兼容解决方案,您可以轻松地重用.
Here's my attempt at a general C++11-compliant solution that you can easily reuse.
让我们从创建一个简单的 type trait 开始,该特征将 void
转换为空结构.这不会引入任何代码重复.
Let's start by creating a simple type trait that converts void
to an empty struct. This doesn't introduce any code repetition.
struct nothing { };
template <typename T>
struct void_to_nothing
{
using type = T;
};
template <>
struct void_to_nothing<void>
{
using type = nothing;
};
template <typename T>
using void_to_nothing_t = typename void_to_nothing<T>::type;
我们还需要一种方法来调用任意函数,将最终的 void
返回类型转换为 nothing
:
We also need a way to call an arbitrary function converting an eventual void
return type to nothing
:
template <typename TReturn>
struct helper
{
template <typename TF, typename... Ts>
TReturn operator()(TF&& f, Ts&&... xs) const
{
return std::forward<TF>(f)(std::forward<Ts>(xs)...);
}
};
template <>
struct helper<void>
{
template <typename TF, typename... Ts>
nothing operator()(TF&& f, Ts&&... xs) const
{
std::forward<TF>(f)(std::forward<Ts>(xs)...);
return nothing{};
}
};
template <typename TF, typename... Ts>
auto with_void_to_nothing(TF&& f, Ts&&... xs)
-> void_to_nothing_t<
decltype(std::forward<TF>(f)(std::forward<Ts>(xs)...))>
{
using return_type =
decltype(std::forward<TF>(f)(std::forward<Ts>(xs)...));
return helper<return_type>{}(std::forward<TF>(f), std::forward<Ts>(xs)...);
}
用法:
template <typename ReturnType, typename ...Args>
void_to_nothing_t<ReturnType> function (Args ...args) {
// prepare for call
// ...
auto rv = with_void_to_nothing(makeCall, args...); // [1]
// dismiss the call
// ...
return rv;
}
马特·卡拉布雷斯(Matt Calabrese)提出的一项提案,称为"无效" ,可以解决此问题.您可以在此处找到:"P0146R1" .
There's a proposal by Matt Calabrese called "Regular Void" that would solve this issue. You can find it here: "P0146R1".
这篇关于在C ++ 11中的模板化函数中处理void变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!