簡體   English   中英

C++ 可變參數模板空參數特化

[英]C++ variadic template empty argument specialization

為空參數可變參數模板編寫專業化的正確方法是什么。 以下面的代碼為例:

#include <iostream>
#include <memory>
#include <tuple>
#include <functional>
#include <cassert>

using namespace std;

struct message {
    int type;
};

struct X: message {
    int payload;
    X(): message{1} {
    }
};

struct Y: message {
    int payload;
    Y(): message{2} {
    }
};

struct Z: message {
    int payload;
    Z(): message{3} {
    }
};

template<typename T>
constexpr int message_type = -1;

template<>
constexpr int message_type<X> = 1;

template<>
constexpr int message_type<Y> = 2;

template<>
constexpr int message_type<Z> = 3;

struct M {
    int payload;
    M(int payload): payload{ payload } {
    }
};

template<typename P, typename T1, typename... Ts>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg, function<int(unique_ptr<T1>&)> fn1, function<int(unique_ptr<Ts>&)>... fn) {
    if (msg->type == message_type<T1>) {
        unique_ptr<T1> m(static_cast<T1*>(msg.release()));
        auto result = fn1(m);
        return {result, make_unique<M>(m->payload)};
    } else {
        return helper<void, Ts...>(msg, fn...);
    }
}

template<typename P>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg) {
    assert(false);
    return {0, unique_ptr<M>()};
}

template<typename... Ts>
tuple<int, unique_ptr<M>> dispatch_msg(unique_ptr<message> &msg, function<int(unique_ptr<Ts>&)> ...fn) {
    return helper<void, Ts...>(msg, fn...);
}

int main() {
    auto *real_message = new Z;
    real_message->payload = 101;

    unique_ptr<message> msg(real_message);

    auto [result, m] = dispatch_msg<X, Y, Z>(msg, [](auto &x) {
        return x->payload + 1;
    }, [](auto &y) {
        return y->payload + 2;
    }, [](auto &z) {
        return z->payload + 3;
    });
    cout << result << '\n' << m->payload << endl;
    return 0;
}

helper function 采用可變參數模板 arguments。 如果它檢查了所有給定類型 arguments 並失敗。 例如運行到空的 arguments。 我想斷言並停止該過程。 當前代碼有效,但我想知道是否有任何直接的方法來編寫專業化。

我將核心要求簡化為以下代碼:

template<typename T, typename... Ts>
void func(int val, T arg, Ts... args) {
    if (condition_hold<T>(val)) {
        return;
    } else {
        return func<Ts...>(val, args...);
    }
}

template<>
void func(int val) {
    assert(false);
}

int main() {
    func<int, double, float>(100);
    return 0;
}

基本上,該func正在檢查每個給定類型是否符合輸入val的條件。 如果所有檢查都失敗了,我想做一些事情,比如這里的assert 所以我寫了一個專業化的空參數,但這無法編譯。

在 C++17 中,大多數情況下您不需要將參數包拆分為頭部和尾部。 多虧了折疊表達式,對包的許多操作變得更加容易。

// Some generic predicate.
template <typename T>
bool condition_hold(T) {
    return true;
}

// Make this whatever you want.
void do_something_with(int);

template<typename... Ts>
auto func(int val, Ts... args) {
    // Fold expression checks whether the condition is true for all
    // elements of the parameter pack.
    // Will be true if the parameter pack is empty.
    if ((condition_hold(args) && ...))
        do_something_with(val);
}

int main() {
    // Ts type parameters are deduced to <float, float>.
    func(100, 1.f, 2.f);
    return 0;
}

要檢查包裝是否為空並專門處理這種情況,您可以執行以下操作:

template<typename... Ts>
auto func(int val, Ts... args) {
    if constexpr (sizeof...(Ts) == 0) {
        // handle empty pack
    }
    else {
        // handle non-empty pack
    }
}

由於func<>需要至少一個參數,因此您的專業化無法奏效。 專業如

template<typename T>
void func<T>(int val);

也不是有效的,因為它是只允許類的部分專業化。 但是,如果基本模板只需要一個包,我們可以完全專門化它:

template<typename... Ts>
void func(int val, Ts... args);

template<>
void func<>(int val);

暫無
暫無

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

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