我有以下模板和专业化(此代码不正确,但希望能很好地证明我的意图):
template <typename T> widget &&make_widget(T &&val) { // (1)
return std::move(widget(std::forward<T>(val)));
}
template <> widget &&make_widget(void) { // (2)
return std::move(widget());
}
目的是拥有一个可以像这样调用的工厂函数:
make_widget(arbitrary_function());
如果arbitrary_function
返回void
,请选择默认构造函数。
然而,对于clang 3.7,我收到以下错误:
error: no function template matches function template specialization 'make_widget'
指向(2)的行。我该如何正确实现?
答案 0 :(得分:2)
你不能这样做。创建具有void
类型参数的函数是不可能的。你可以做的是使函数变量,如make_unique
。
template <typename... T>
widget make_widget(T&&... val) {
return widget(std::forward<T>(val)...);
}
然后,如果你想做像
这样的事情auto w = make_widget(void_function());
没有什么可以阻止你做的事情:
void_function();
auto w = make_widget();
甚至,如果你因某种原因确实需要它作为一个陈述,
auto w = (void_function(), make_widget());
另外三个注意事项:
std::move
,因为调用构造函数的结果已经是一个右值。make_widget
函数如果将其参数转发给widget
构造函数是唯一那么就没有意义。请注意make_unique
负责为您调用new
,make_tuple
推断tuple
本身的模板参数。您的make_widget
功能无法执行此类操作。答案 1 :(得分:1)
正如已经指出的那样,问题不在于模板专业化,而是在使用void表达式。
但是,我可以建议使用中间lambda和辅助模板的替代语法,以一点点可忽略的额外使用语法为代价来实现相同的结果。public void addAtLocation(int location, string element)
{
string[] newMyArray = new string[myArray.Length + 1];
Array.Copy(myArray, 0, newMyArray, 0, location);
newMyArray[location] = element;
Array.Copy(myArray, location, newMyArray, location + 1, myArray.Length - location);
myArray = newMyArray;
}
在-std = c ++ 14模式下用g ++ 5.1.1测试上面的内容,我似乎用以下语法得到了正确的结果,这几乎是你想要完成的事情:
#include <functional>
class widget {
public:
widget();
widget(int);
};
template <typename T> widget &&do_make_widget(T &&val) { // (1)
return std::move(widget(std::forward<T>(val)));
}
widget &&do_make_widget() { // (2)
return std::move(widget());
}
template <typename T>
class do_make_widget_invoke {
public:
template<typename functor_type>
static auto invoke(functor_type &&functor)
{
return do_make_widget(functor());
}
};
template <>
class do_make_widget_invoke<void> {
public:
template<typename functor_type>
static auto invoke(functor_type &&functor)
{
functor();
return do_make_widget();
}
};
template<typename functor_type>
auto make_widget(functor_type &&functor)
{
return do_make_widget_invoke<decltype(functor())>
::invoke(std::forward<functor_type>(functor));
}
和
int foobar()
{
return 0;
}
int main()
{
make_widget([]{ return foobar(); });
}