簡體   English   中英

C ++元編程自動函數創建?

[英]C++ metaprogramming automatic function creation?

我不確定標題是否正確但這是我的問題/問題:

我想使用元編程來創建特定表達式的函數。 例如,假設我們有這樣的代碼:

template<typename T1, typename T2>
struct plus{
    T1 func(T1 in1, T2 in2){ return in1 + in2; }
};

template<typename T1, typename T2, typename T3, typename expr>
struct wrap{

    /* contain a func that can evaluate the expr */
};

並且程序員將編寫下面的代碼以便為表達式創建函數:

wrap<int,int,int,plus<plus<int,int>,int> >::func(1,2,3); /*result should be 6*/

這可能嗎?

謝謝。

#include <utility>
#include <tuple>
#include <cstddef>

struct arg
{
    template <typename Arg1>
    static constexpr decltype(auto) apply(Arg1&& arg1)
    {
        return std::forward<Arg1>(arg1);
    }

    static constexpr std::size_t arity = 1;
};

template <typename Type, Type value>
struct constant
{    
    static constexpr decltype(auto) apply()
    {
        return value;
    }

    static constexpr std::size_t arity = 0;
};

template <typename Lhs, typename Rhs>
struct plus
{
    template <typename... Args>
    static constexpr decltype(auto) apply(Args&&... args)
    {
        return _apply(std::make_index_sequence<Lhs::arity>{}, std::make_index_sequence<Rhs::arity>{}, std::tuple<Args&&...>(std::forward<Args>(args)...));
    }

    template <typename Tuple, std::size_t... Arity1, std::size_t... Arity2>
    static constexpr decltype(auto) _apply(std::index_sequence<Arity1...>, std::index_sequence<Arity2...>, Tuple&& args)
    {
        return Lhs::apply(static_cast<typename std::tuple_element<Arity1, Tuple>::type>(std::get<Arity1>(args))...)
             + Rhs::apply(static_cast<typename std::tuple_element<Lhs::arity + Arity2, Tuple>::type>(std::get<Lhs::arity + Arity2>(args))...);
    }

    static constexpr std::size_t arity = Lhs::arity + Rhs::arity;
};

template <typename Lhs, typename Rhs>
struct multiply
{
    template <typename... Args>
    static constexpr decltype(auto) apply(Args&&... args)
    {
        return _apply(std::make_index_sequence<Lhs::arity>{}, std::make_index_sequence<Rhs::arity>{}, std::tuple<Args&&...>(std::forward<Args>(args)...));
    }

    template <typename Tuple, std::size_t... Arity1, std::size_t... Arity2>
    static constexpr decltype(auto) _apply(std::index_sequence<Arity1...>, std::index_sequence<Arity2...>, Tuple&& args)
    {
        return Lhs::apply(static_cast<typename std::tuple_element<Arity1, Tuple>::type>(std::get<Arity1>(args))...)
             * Rhs::apply(static_cast<typename std::tuple_element<Lhs::arity + Arity2, Tuple>::type>(std::get<Lhs::arity + Arity2>(args))...);
    }

    static constexpr std::size_t arity = Lhs::arity + Rhs::arity;
};

測試:

int main()
{
    // (1 + 2) + 3 = 6
    std::cout << plus<plus<arg, arg>, arg>::apply(1, 2, 3) << std::endl;

    // (a + 5) + (2 * 6) = 9 + 12 = 21
    int a = 4;
    std::cout << plus<plus<arg, arg>, multiply<arg, constant<int, 6>>>::apply(a, 5, 2) << std::endl;

    // ((1 * 2) * 3) * 4 = 24
    std::cout << multiply<multiply<multiply<arg, arg>, arg>, arg>::apply(1, 2, 3, 4) << std::endl;

    // 2 + (4 * 5) = 22
    static_assert(plus<arg, multiply<arg, arg>>::apply(2, 4, 5) == 22, "!");
}

輸出:

6
21
24

演示1


可以改進上面的解決方案,以便引入新的仿函數需要更少的工作量,並且聲明本身更具可讀性,如下所示:

#include <iostream>
#include <utility>
#include <tuple>
#include <cstddef>

template <std::size_t Arity>
struct expression
{    
    static constexpr std::size_t arity = Arity;
};

template <typename Expr, typename Rhs>
struct unary_expression : expression<Rhs::arity>
{    
    template <typename... Args>
    static constexpr decltype(auto) apply(Args&&... args)
    {
        static_assert(sizeof...(Args) == unary_expression::arity, "Wrong number of operands!");
        return Expr::eval(Rhs::apply(std::forward<Args>(args)...));
    }
};

template <typename Expr, typename Lhs, typename Rhs>
struct binary_expression : expression<Lhs::arity + Rhs::arity>
{
    template <typename... Args>
    static constexpr decltype(auto) apply(Args&&... args)
    {
        static_assert(sizeof...(Args) == binary_expression::arity, "Wrong number of operands!");
        return _apply(std::make_index_sequence<Lhs::arity>{}, std::make_index_sequence<Rhs::arity>{}, std::tuple<Args&&...>(std::forward<Args>(args)...));
    }

    template <typename Tuple, std::size_t... Arity1, std::size_t... Arity2>
    static constexpr decltype(auto) _apply(std::index_sequence<Arity1...>, std::index_sequence<Arity2...>, Tuple&& args)
    {
        return Expr::eval(Lhs::apply(static_cast<typename std::tuple_element<Arity1, Tuple>::type>(std::get<Arity1>(args))...),
                          Rhs::apply(static_cast<typename std::tuple_element<Lhs::arity + Arity2, Tuple>::type>(std::get<Lhs::arity + Arity2>(args))...));
    }
};

struct arg : expression<1>
{
    template <typename Arg1>
    static constexpr decltype(auto) apply(Arg1&& arg1)
    {
        return std::forward<Arg1>(arg1);
    }
};

template <typename Type, Type value>
struct constant : expression<0>
{    
    static constexpr decltype(auto) apply()
    {
        return value;
    }
};

template <typename Rhs>
struct negate : unary_expression<negate<Rhs>, Rhs>
{
    template <typename Arg1>
    static constexpr decltype(auto) eval(Arg1&& arg1)
    {
        return -std::forward<Arg1>(arg1);
    }
};

template <typename Lhs, typename Rhs>
struct plus : binary_expression<plus<Lhs, Rhs>, Lhs, Rhs>
{
    template <typename Arg1, typename Arg2>
    static constexpr decltype(auto) eval(Arg1&& arg1, Arg2&& arg2)
    {
        return std::forward<Arg1>(arg1) + std::forward<Arg2>(arg2);
    }
};

template <typename Lhs, typename Rhs>
struct minus : binary_expression<minus<Lhs, Rhs>, Lhs, Rhs>
{
    template <typename Arg1, typename Arg2>
    static constexpr decltype(auto) eval(Arg1&& arg1, Arg2&& arg2)
    {
        return std::forward<Arg1>(arg1) - std::forward<Arg2>(arg2);
    }
};

template <typename Lhs, typename Rhs>
struct multiply : binary_expression<multiply<Lhs, Rhs>, Lhs, Rhs>
{
    template <typename Arg1, typename Arg2>
    static constexpr decltype(auto) eval(Arg1&& arg1, Arg2&& arg2)
    {
        return std::forward<Arg1>(arg1) * std::forward<Arg2>(arg2);
    }
};

int main()
{    
    // (1 + 2) + 3 = 6
    std::cout << plus<plus<arg, arg>, arg>::apply(1, 2, 3) << std::endl;

    // ((a + 5) + (2 * 6)) - 5 = 16
    int a = 4;
    std::cout << minus<plus<plus<arg, arg>, multiply<arg, constant<int, 6>>>, constant<int, 5>>::apply(a, 5, 2) << std::endl;

    // ((1 * 2) * 3) * 4 = 24
    std::cout << multiply<multiply<multiply<arg, arg>, arg>, arg>::apply(1, 2, 3, 4) << std::endl;

    // -((3 * 4) + (5 - 6)) = -11
    static_assert(negate<plus<multiply<arg, arg>, minus<arg, arg>>>::apply(3, 4, 5, 6) == -11, "!");
}

演示2

絕對。 這些被稱為“表達模板”,你可以在這里找到SO的亮點。

我在90年代后期開始使用POOMA系統進行並行編程。 不知道它已經更新到現代化的標准,但我看到它仍然可在網上點擊這里 底層POOMA是一個名為PETE的“表達模板引擎”,可以重新用於其他評估引擎。 PETE 在這里描述。 使用C ++ 11,所有這些工作都會簡單得多,我確信有類似的工作可以使用這些新功能。

暫無
暫無

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

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