可变参数模板的功能组合

钥匙

我的目标是使用以下确切语法来构成函数

int main() {
    Function<std::string, int> f([](const std::string& s) {return s.length();});
    Function<int, double> g([](int x) {return x + 0.5;});
    Function<double, int> h([](double d) {return int(d+1);});
    std::cout << compose(g, f, "hello") << '\n';  // g(f("hello")) = 5.5
    std::cout << compose(h, g, f, "hello") << '\n';  // h(g(f("hello"))) = 6
}

通过稍微更改语法以使"hello"参数优先,我可以轻松地使用以下代码:

#include <iostream>
#include <functional>
#include <tuple>
#include <string>

template <typename D, typename R>
struct Function {
    using domain = const D&;
    using range = R;
    using function = std::function<range(domain)>;
    const function& f;
    Function (const function& f) : f(f) {}
    range operator()(domain x) const {return f(x);}
};

template <typename... Ts>
struct LastType {
    using Tuple = std::tuple<Ts...>;
    using type = typename std::tuple_element<std::tuple_size<Tuple>::value - 1, Tuple>::type;
};

template <typename F, typename G>
typename G::range compose (const typename F::domain& x, const G& g, const F& f) {
    return g(f(x));
}

template <typename F, typename... Rest>
auto compose (const typename LastType<Rest...>::type::domain& x, const F& f, const Rest&... rest) {
    return f(compose(x, rest...));
}

int main() {
    Function<std::string, int> f([](const std::string& s) {return s.length();});
    Function<int, double> g([](int x) {return x + 0.5;});
    Function<double, int> h([](double d) {return int(d+1);});
    std::cout << compose("hello", g, f) << '\n';  // g(f("hello")) = 5.5
    std::cout << compose("hello", h, g, f) << '\n';  // h(g(f("hello"))) = 6
}

完成此操作后,我认为对上述代码进行修改将是一件微不足道的任务,以便获得所需的确切语法(即,“ hello”位于列表的末尾),但它比我想象的要困难得多。我尝试了以下无法编译的内容:

#include <iostream>
#include <functional>
#include <tuple>
#include <string>

template <typename D, typename R>
struct Function {
    using domain = const D&;
    using range = R;
    using function = std::function<range(domain)>;
    const function& f;
    Function (const function& f) : f(f) {}
    range operator()(domain x) const {return f(x);}
};

template <typename F, typename G>
typename G::range compose (const G& g, const F& f, const typename F::domain& x) {
    return g(f(x));
}

template <typename F, typename... Rest>
auto compose (const F& f, const Rest&... rest) {
    return f(compose(rest...));
}

int main() {
    Function<std::string, int> f([](const std::string& s) {return s.length();});
    Function<int, double> g([](int x) {return x + 0.5;});
    Function<double, int> h([](double d) {return int(d+1);});
    std::cout << compose(g, f, "hello") << '\n';  // g(f("hello")) = 5.5
    std::cout << compose(h, g, f, "hello") << '\n';  // h(g(f("hello"))) = 6
}

而且我不知道如何解决它。有人可以帮我解决这个问题吗?

我想到的一个新想法是定义compose_,它将args...(通过某种std::tuple操纵)对自变量进行重新排序,以便第一个元素排在最后,然后将该自变量包传递给compose但是,这看起来很混乱,即使可行,也必须有一个更直接(更短)的解决方案。

最高66

这样呢?

#include <iostream>    
#include <functional>
#include <tuple>
#include <string>

template <typename D, typename R>
struct Function {
    using domain = const D&;
    using range = R;
    using function = std::function<range(domain)>;
    const function& f;
    Function (const function& f) : f(f) {}
    range operator()(domain x) const {return f(x);}
};

template <typename F, typename X = typename F::domain>
typename F::range compose (const F& f, const X & x) {
    return f(x);
}

template <typename F, typename... Rest>
typename F::range  compose (const F& f, const Rest&... rest) {
    return f(compose(rest...));
}

int main() {
    Function<std::string, int> f([](const std::string& s) {return    s.length();});
    Function<int, double> g([](int x) {return x + 0.5;});
    Function<double, int> h([](double d) {return int(d+1);});
    std::cout << compose(g, f, "hello") << '\n';  // g(f("hello")) = 5.5
    std::cout << compose(h, g, f, "hello") << '\n';  // h(g(f("hello"))) = 6
}

只能在c ++ 14中将其auto用作返回类型compose()(如果我没记错的话)。

您的版本无法编译,因为 compose() 当最终(非变数)使用2个类型和3个参数时,您的可变版本 使用N个可变类型和N个参数。换句话说,可变参数版本失去了最终论点。 您的版本无法编译,因为从未使用最终版本(非可变版本):编译器选择可变版本。添加typename X = typename F::domain(和改变const typename F::domain&const X&)的最终版本是优选的并且您的代码应编译(用C ++ 14,至少)[由彼得Skotnicki纠正; 谢谢]

ps:对不起,我的英语不好。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章