使一个函数接受一个可选的接受非可选的?

YSC*_*YSC 47 c++ templates optional template-argument-deduction c++17

我正在尝试以monad风格编写语法糖std::optional.请考虑:

template<class T>
void f(std::optional<T>)
{}
Run Code Online (Sandbox Code Playgroud)

即使存在从22的转换,也不能使用非可选T1(例如an int)调用此函数.Tstd::optional<T>

有没有办法f接受a std::optional<T>或a T(在调用者站点转换为可选),而没有定义过载3


1) f(0):error: no matching function for call to 'f(int)'note: template argument deduction/substitution failed,(演示).
2)因为模板参数推导不考虑转换.
3)超载是用于一个一元函数的可接受的解决方案,但开始是当你有像二进制功能的烦恼operator+(optional, optional),并且是用于三元疼痛,4元,等等功能.

Bar*_*rry 38

另一个版本.这个不涉及任何事情:

template <typename T>
void f(T&& t) {
    std::optional opt = std::forward<T>(t);
}
Run Code Online (Sandbox Code Playgroud)

类模板参数推导已经在这里做了正确的事情.如果toptional,则复制扣除候选者将是首选,我们将返回相同的类型.否则,我们包装它.

  • @LThode非常没有. (7认同)
  • 虽然这不是代码高尔夫,但我觉得这个答案值得勾选:D (3认同)
  • @Barry - a-ha,我明白你的意思了 - 我以前从未碰到过类模板参数演绎! (3认同)

bar*_*top 15

取代可选的参数作为参数取得可抵扣的模板参数:

template<class T>
struct is_optional : std::false_type{};

template<class T>
struct is_optional<std::optional<T>> : std::true_type{};

template<class T, class = std::enable_if_t<is_optional<std::decay_t<T>>::value>>
constexpr decltype(auto) to_optional(T &&val){
    return std::forward<T>(val);
}

template<class T, class = std::enable_if_t<!is_optional<std::decay_t<T>>::value>>
constexpr std::optional<std::decay_t<T>> to_optional(T &&val){
    return { std::forward<T>(val) };
}

template<class T>
void f(T &&t){
    auto opt = to_optional(std::forward<T>(t));
}

int main() {
    f(1);
    f(std::optional<int>(1));
}
Run Code Online (Sandbox Code Playgroud)

实例


xax*_*xon 13

这使用了我最喜欢的类型特征之一,可以根据类型检查任何所有类型的模板,看它是否是它的模板.

#include <iostream>
#include <type_traits>
#include <optional>


template<template<class...> class tmpl, typename T>
struct x_is_template_for : public std::false_type {};

template<template<class...> class tmpl, class... Args>
struct x_is_template_for<tmpl, tmpl<Args...>> : public std::true_type {};

template<template<class...> class tmpl, typename... Ts>
using is_template_for = std::conjunction<x_is_template_for<tmpl, std::decay_t<Ts>>...>;

template<template<class...> class tmpl, typename... Ts>
constexpr bool is_template_for_v = is_template_for<tmpl, Ts...>::value;


template <typename T>
void f(T && t) {
    auto optional_t = [&]{
        if constexpr (is_template_for_v<std::optional, T>) {
            return t; 
        } else {
            return std::optional<std::remove_reference_t<T>>(std::forward<T>(t));
        }
    }();
    (void)optional_t;
}

int main() {
    int i = 5;
    std::optional<int> oi{5};

    f(i);
    f(oi);
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/HXgoEE

  • @YSC没有`std :: decay`它不会像`std :: optional <int>&`和相关类型那样自动运行 (2认同)

Bar*_*rry 5

另一个版本.这个不涉及写作特征:

template <typename T>
struct make_optional_t {
    template <typename U>
    auto operator()(U&& u) const {
        return std::optional<T>(std::forward<U>(u));
    }
};

template <typename T>
struct make_optional_t<std::optional<T>> {
    template <typename U>
    auto operator()(U&& u) const {
        return std::forward<U>(u);
    }
};

template <typename T>
inline make_optional_t<std::decay_t<T>> make_optional;

template <typename T>
void f(T&& t){
    auto opt = make_optional<T>(std::forward<T>(t));
}
Run Code Online (Sandbox Code Playgroud)