我有三个示例程序,其中两个编译,另一个不编译。所有这三个都是使用g ++ 4.8.1编译的,使用命令行:g++ --std=c++11 -Wall -pedantic -o foo foo.cc
。有问题的代码是一个用于展示问题的遗留示例,并不意味着它本身就是有用的。
底层问题是一个模板化的类,需要专门化来处理std::promise<void>::set_value()
不带参数的事实。这个问题出现在Foo::_call()
方法中。
我想要使用的版本,称之为版本A,失败:
#include <future>
template <typename A, typename T>
class Foo
{
private:
std::function<T ()> _f;
std::promise<T> _p;
static void _call(std::function<T ()> &f, std::promise<T> &p) {
p.set_value(f());
}
public:
Foo(std::function<T ()> x) : _f(x) {}
void set_promise() {
_call(_f, _p);
}
};
template<typename A>
inline void Foo<A, void>::_call(
std::function<void ()> &f, std::promise<void> &p)
{
f();
p.set_value();
}
int bar()
{
return 4;
}
void baz()
{
}
int main()
{
Foo<int, int> a(bar);
a.set_promise();
Foo<int, void> b(baz);
b.set_promise();
}
错误是:
foo.cc:24:53: error: invalid use of incomplete type ‘class Foo<A, void>’
std::function<void ()> &f, std::promise<void> &p)
^
foo.cc:4:7: error: declaration of ‘class Foo<A, void>’
class Foo
^
foo.cc: In instantiation of ‘static void Foo<A, T>::_call(std::function<_Res()>&, std::promise<T>&) [with A = int; T = void]’:
foo.cc:18:21: required from ‘void Foo<A, T>::set_promise() [with A = int; T = void]’
foo.cc:44:19: required from here
foo.cc:11:9: error: invalid use of void expression
p.set_value(f());
^
以下测试,B,编译。它会将额外的模板参数A
取出到Foo
。在实践中,我不想要这个,因为我的非玩具类需要这个参数。
#include <future>
template <typename T>
class Foo
{
private:
std::function<T ()> _f;
std::promise<T> _p;
static void _call(std::function<T ()> &f, std::promise<T> &p) {
p.set_value(f());
}
public:
Foo(std::function<T ()> x) : _f(x) {}
void set_promise() {
_call(_f, _p);
}
};
template<>
void Foo<void>::_call(
std::function<void ()> &f, std::promise<void> &p)
{
f();
p.set_value();
}
int bar()
{
return 4;
}
void baz()
{
}
int main()
{
Foo<int> a(bar);
a.set_promise();
Foo<void> b(baz);
b.set_promise();
}
测试C也编译。它将_call()
静态方法从Foo
中拉出,成为模板化函数。我也不愿意这样做,因为_call
意味着属于Foo
。虽然这很有效,但它还不够优雅。
#include <future>
template<typename T>
inline void _call(std::function<T ()> &f, std::promise<T> &p)
{
p.set_value(f());
}
template<>
void _call(std::function<void ()> &f, std::promise<void> &p)
{
f();
p.set_value();
}
template <typename A, typename T>
class Foo
{
private:
std::function<T ()> _f;
std::promise<T> _p;
public:
Foo(std::function<T ()> x) : _f(x) {}
void set_promise() {
_call(_f, _p);
}
};
int bar()
{
return 4;
}
void baz()
{
}
int main()
{
Foo<int, int> a(bar);
a.set_promise();
Foo<int, void> b(baz);
b.set_promise();
}
所以,问题是,为什么A失败了?有没有办法解决这个问题而不诉诸B或C?
答案 0 :(得分:3)
部分模板专门化仅适用于整个类模板。你不能只对一个成员进行部分专业化。
一种解决方案是引入基类并将其专门化。
#include <future>
template< typename T >
struct Foo_base {
static void _call(std::function<T ()> &f, std::promise<T> &p) {
p.set_value(f());
}
};
template<>
struct Foo_base< void > {
static void _call(std::function<void ()> &f, std::promise<void> &p)
{
f();
p.set_value();
}
};
template <typename A, typename T>
class Foo : Foo_base< T >
{
private:
using Foo::Foo_base::_call;
std::function<T ()> _f;
std::promise<T> _p;
public:
Foo(std::function<T ()> x) : _f(x) {}
void set_promise() {
_call(_f, _p);
}
};