簡體   English   中英

將 std::enable_if 與外部成員函數和模板化靜態成員條件一起使用

[英]Using std::enable_if with out-of-line member functions and templated static member conditions

我想使用 SFINAE 創建一個模板化的成員函數,它接受一個Consumer函子。 某個東西是否是消費者取決於模板化的static constexpr bool isConsumer成員變量。 我已將代碼簡化為以下示例:

#include <type_traits>

template <typename T>
struct Container {
    T data[100];

    template <typename Consumer>
    static constexpr bool isConsumer = std::is_invocable_r_v<void, Consumer, T>;

    template <typename Consumer, std::enable_if_t<isConsumer<Consumer>, int> = 0>
    void forEach(const Consumer &consumer);
};

template <typename T>
template <typename Consumer, std::enable_if_t<Container<T>::template isConsumer<Consumer>, int>>
void Container<T>::forEach(const Consumer &consumer)
{
    for (int i = 0; i < 100; ++i) {
        consumer(data[i]);
    }
}

由於我不理解的原因,這不會編譯:

<source>:16:20: error: out-of-line definition of 'forEach' does not match any declaration in 'Container<T>'

void Container<T>::forEach(const Consumer &consumer)

                   ^~~~~~~

當我內聯isConsumer ,它確實編譯得很好,就像直接使用std::is_invocable_r_v 我想避免這種情況,因為在我的真實代碼中, Consumer的簽名非常復雜,這需要相當多的復制/粘貼。

isConsumer類之外也不是一種選擇,因為在我的實際代碼中,它取決於Container內的私有 typedef。 它必須在類內部。

我如何在這里正確使用std::enable_if

鑒於當前聲明,似乎確實沒有辦法做出外線定義(gcc 抱怨聲明使用了“匿名類型”)

可能的解決方法:

使用static_assert而不是 SFINAE:

#include <type_traits>

template <typename T>
struct Container {
    template <typename Consumer>
    static constexpr bool isConsumer = /* ... */;

    template <typename Consumer>
    void forEach(const Consumer &consumer);
};

template <typename T>
template <typename Consumer>
void Container<T>::forEach(const Consumer &consumer)
{
    static_assert(isConsumer<Consumer>);
    // ...
}

也完全限定聲明,因此定義應該引用相同的類型(這在clang中不起作用。似乎是clang錯誤):

#include <type_traits>

template <typename T>
struct Container {
    template <typename Consumer>
    static constexpr bool isConsumer = /* ... */;

    template <typename Consumer, std::enable_if_t<Container<T>::template isConsumer<Consumer>, int> = 0>
    void forEach(const Consumer &consumer);
};

template <typename T>
template <typename Consumer, std::enable_if_t<Container<T>::template isConsumer<Consumer>, int>>
void Container<T>::forEach(const Consumer &consumer)
{
    // ...
}

委托給一個帶有小的轉發內部函數的私有函數:

#include <type_traits>

template <typename T>
struct Container {
    template <typename Consumer>
    static constexpr bool isConsumer = /* ... */;

    template <typename Consumer, std::enable_if_t<isConsumer<Consumer>, int> = 0>
    void forEach(const Consumer &consumer) {
        forEachImpl(consumer);
    }
private:
    template<typename Consumer>
    void forEachImpl(const Consumer&);
};

template<typename T>
template<typename Consumer>
void Container<T>::forEachImpl(const Consumer& consumer) {
    // ...
}

改用返回類型 SFINAE,這樣您就可以在類的命名空間中進行查找:

#include <type_traits>

template <typename T>
struct Container {
    template <typename Consumer>
    static constexpr bool isConsumer = /* ... */;

    template <typename Consumer>
    std::enable_if_t<isConsumer<Consumer>> forEach(const Consumer &consumer);
};

template <typename T>
template <typename Consumer>
auto Container<T>::forEach(const Consumer &consumer) -> std::enable_if_t<isConsumer<Consumer>>
{
    // ...
}

當然,只是內聯定義它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM