Constexpr重载模板函数的别名

use*_*336 7 c++ templates constexpr

尝试在特定类类型上为该类的特定构造函数设置make_shared别名.我最好的尝试:

class foo { public: foo(int x) : y(x) {} int y; };
constexpr auto newfoo = static_cast<std::shared_ptr<foo>(*)(int)>(std::make_shared<foo>);
Run Code Online (Sandbox Code Playgroud)

产量:

error: invalid static_cast from type ‘<unresolved overloaded function type>’ to type ‘std::shared_ptr<foo> (*)(int)’
constexpr auto newfoo = static_cast<std::shared_ptr<foo>(*)(int)>(std::make_shared<foo>);
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Vit*_*meo 4

std::make_shared是一个可变参数函数模板。您仅指定<foo>为模板参数,但您还需要int其中的某个位置。无论如何,您的方法注定会失败,因为make_shared它依赖于模板参数的布局方式,并且在 C++ 中使用重载集通常很麻烦。

我的建议是创建一个包装函数:

constexpr auto newfoo(int x)
{
    return std::make_shared<foo>(x);
}
Run Code Online (Sandbox Code Playgroud)

在我看来,它更容易编写、阅读和理解。如果您确实需要 SFINAE 友好性并且noexcept,您可以重复正文三遍

constexpr auto newfoo(int x) 
    ->          decltype(std::make_shared<foo>(x))
       noexcept(noexcept(std::make_shared<foo>(x)))
      {           return std::make_shared<foo>(x); }
Run Code Online (Sandbox Code Playgroud)

可以使用宏来使上述声明不那么痛苦。


如果你真的想要一个函数指针,这似乎可行:

auto newfoo = 
    static_cast<std::shared_ptr<foo>(*)(const int&)>(
        &std::make_shared<foo, const int&>);
Run Code Online (Sandbox Code Playgroud)

看一下make_shared的声明:

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
Run Code Online (Sandbox Code Playgroud)

你需要供应T=foo一些东西Args...。由于Args...是转发引用包,因此它总是会推导出左值引用右值引用。这就是为什么<foo, const int&>是一组有效的模板参数而<foo, int>不是。

正如泽菲克在评论中指出的那样,所有这些都可以简化为:

constexpr auto newfoo = &std::make_shared<foo, const int&>;
Run Code Online (Sandbox Code Playgroud)

这里并不真正需要演员阵容。

  • `constexpr auto newfoo = std::make_shared&lt;foo, int&gt;` 就可以了。为什么我们需要演员阵容? (3认同)