禁用与SFINAE模板类的成员函数

问题描述 投票:1回答:2

假设我有一个接受某种类型T类。这意味着它可以接受一些类型optional<U>。我想禁用的功能,如果它是一个optional类型的不是,但如果是...那么我想知道这种类型U

我已经能够通过模板禁用此功能,但我不知道如何处理检测模板模板类,而不写两次同一类,使一个模板化的模板版本。

Code

class Dummy{};

template <typename T>
class C {
    T t;

public:
    C(T t) : t(std::move(t)) { }

    T get() {
        return t;
    }

    // Will clearly fail when T doesn't have a value_type
    template <typename R = T, typename OptT = typename T::value_type, typename = std::enable_if_t<std::is_same_v<T, optional<OptT>>>>
    std::vector<OptT> stuff() {
        std::vector<OptT> vec;
        // Do stuff, fill vec
        return vec;
    }
};

int main() {
    C<Dummy> c{Dummy()};                // Error
    // C<optional<Dummy>> c{Dummy()};   // Works fine
    c.get();
}

在这一过程中,我得到

main.cpp中:在“C类”实例化:

main.cpp中:33:14:从这里需要

main.cpp中:25:23:错误:没有键入 '类假' 命名为 'VALUE_TYPE'

 std::vector<OptT> stuff() {

                   ^~~~~

注:这是好的,如果有这个类的一个特例,如果std::optional我所关心的是检测。我并不需要它的任何其他类型的...只有可选的工作。这可允许某种模板专业化的,但我也没弄清楚如何研究,当它这样做。

我怎样才能让这个功能只有当类型为std::optional出现,然后当它是那种类型,能够抓住可选的内部类型?我能做到这一点不沾T的模板定义? (如在,我可以做到这一点,而把它当作template <typename T>而不改变它template <template <typename> T>或具有复制此类,其中上述两种制成)

c++ templates c++17 sfinae
2个回答
2
投票

你的问题就在这里:

// Will clearly fail when T doesn't have a value_type
template <typename R = T,
          typename OptT = typename T::value_type,
          typename = std::enable_if_t<std::is_same_v<T, optional<OptT>>>>

这是你推出一个新的虚拟模板参数,R,但你还在使用旧的,T,你所有的检查。所以没有检查实际上是相关的。 SWAP他们R和你的罚款。


一种不同的方法是推迟到只使用一个标签参数不同的功能:

template <typename> struct tag { };

template <typename R=T>
auto stuff() -> decltype(stuff_impl(tag<R>{})) {
    return stuff_impl(tag<R>{});
}

现在在哪里,你可以有效地只使用Normal模板扣拉出类型:

template <typename U>
std::vector<U> stuff_impl(tag<std::optional<U>>) {
    return {};
}

2
投票

我的建议如下定义自定义类型特征

template <typename>
struct optionalType
 { };

template <typename T>
struct optionalType<std::optional<T>>
 { using type = T; };

当且仅当有type调用定义T(该std::optional<T>的类型std::optional)。

现在你的stuff()简直成了

template <typename R = T,
          typename OptT = typename optionalType<R>::type>
std::vector<OptT> stuff() {
    std::vector<OptT> vec;
    // Do stuff, fill vec
    return vec;
}

观察到OptT,所述std::optional的类型,存在仅当R(又名T)是std::optional;你有一个替代的故障,否则,禁止stuff()

您可以验证

C<Dummy>                c0{Dummy()};
C<std::optional<Dummy>> c1{Dummy()};

//c0.stuff(); // compilation error
c1.stuff();   // compile
© www.soinside.com 2019 - 2024. All rights reserved.