专门为void参数设置模板

时间:2015-11-12 21:07:37

标签: c++ templates c++14

我有以下模板和专业化(此代码不正确,但希望能很好地证明我的意图):

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)的行。我该如何正确实现?

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());

另外三个注意事项:

  • 你应该在return语句中修改std::move,因为调用构造函数的结果已经是一个右值。
  • 永远不要将参考(甚至右值参考)返回临时!它将永远成为一个悬垂的参考。
  • make_widget函数如果将其参数转发给widget构造函数是唯一那么就没有意义。请注意make_unique负责为您调用newmake_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(); });
}
相关问题