gpt4 book ai didi

c++ - 使用嵌套模板进行模板化

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:37:35 25 4
gpt4 key购买 nike

以下代码不起作用,因为推断的模板参数 F 是 std::tuple,而我希望它是 Foo - 前者有两个模板参数和后者需要一个。

#include <tuple>

template <typename T>
using Foo = std::tuple<int, T>;

template <template <typename> class F>
void foo(F<std::string> bar) {}

void test() {
foo(Foo<std::string>());
}

有什么方法可以使类型推断与 using 语句一起工作,而不是将 Foo 变成它自己的类?

#include <tuple>

template <typename T>
class Foo {
std::tuple<int, T> bar;
};

template <template <typename> class F>
void foo(F<std::string> bar) {}

void test() {
foo(Foo<std::string>());
}

更多信息

我正在使用 C++17 的 std::variant 以及 using 来别名在单个类型上通用的类型,我更愿意使用 using 来声明它们语句,而不是为每个语句创建包装类。像这样:

// Assuming Plus, Minus, etc all exist
template <typename T>
using Operation = std::variant<Plus<T>, Minus<T>, Times<T>>;

构建 Haskell 风格的仿函数

本练习的重点是基于 Haskell 的仿函数类型类松散地构建一个小型仿函数库。我已经这样定义了“类型类”:

template <template <typename> class F>
class Functor {
public:
template <typename T, typename U>
static F<U> fmap(std::function<U(T)> f, F<T> functor);
};

但我还想添加一些糖分,这样您就可以创建一个通用映射器,它将函数映射到任何函数类型上,而无需预先指定仿函数类型:

template <typename T, typename U>
struct FMap {
FMap(std::function<U(T)> f) : f_(f) {}

template <template <typename> class F>
F<U> operator()(F<T> functor) {
return Functor<F>::fmap(f_, functor);
}

private:
std::function<U(T)> f_;
};

template <typename T, typename U>
FMap<T, U> fmap(std::function<U(T)> f) {
return FMap<T, U>(f);
}

这与一个简单的值包装仿函数一起工作得很好:

template <typename T>
class Value {
public:
Value(T value) : value_(value) {}

const T& value() const {
return value_;
}

private:
T value_;
};

template <>
template <typename T, typename U>
Value<U> Functor<Value>::fmap(std::function<U(T)> f, Value<T> value) {
return Value<U>(f(value.value()));
}

void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
auto result = fmap(fn)(Value(42));
// result.value() == "42"
}

现在我正试图让它与使用 std::tuplestd::variant 的更复杂的类型一起工作,如上例所示。

template <>
template <typename T, typename U>
Foo<U> Functor<Foo>::fmap(std::function<U(T)> f, Foo<T> value) {
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}

void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
// This is the desirable syntax but it doesn't build
// fmap(fn)(Foo<int>(42, 7));

// This builds but it's super ugly
fmap(fn).operator()<Foo>(Foo<int>(42, 7));
}

根据下面 SkepticalEmpiricist 的回复,我认为类型别名可能不是解决问题的方法,相反我将不得不引入小型包装类 - 除非有一种 SFINAE 方法可以实现这一点。

这个库主要是出于好奇,也是我探索一些更高级模板概念的一种方式 - 感谢您的帮助!

最佳答案

因此,在我们开始挖掘一些基于 SFINAE 的欺骗手段以尝试规避 the unavoidable 之前,首先尝试:

Alias templates are never deduced by template argument deduction

我们可以像这样“推导出”编译器的模板参数:

#include <tuple>

template <typename T>
using Foo = std::tuple<int, T>;

template <template <typename ...> class F, typename T, typename ...Ts>
void foo(F<T, std::string, Ts...> bar) {}

void test() {
foo(Foo<std::string>());
}

现在我们为您的 foo(Foo<std::string>()); 编译了它用 Foo 打电话作为 std::tuple别名模板而且,更重要的是,foo()仍然专门针对 Foo<std::string> .

但是,支持同时使用foo() 对于std::tuple alias template 和 wrapper class 例如,我们仍然无法编译无错误。比如,如果我们现在注释掉 tuple - flavor Foo并带回包装类 Foo然后调用我们重写的foo() 不会编译

为了解决这个问题,让我们尝试用 SFINAE 来拯救 并替换最后的声明 foo()使用此代码:

template <template <typename ...> class F, typename T, typename ...Ts,
typename std::enable_if_t<std::is_same<F<T, Ts...>,
std::tuple<T, Ts...>>::value >* = nullptr>
void foo(F<T, std::string, Ts...> bar) {}

template <template <typename> class F>
void foo(F<std::string> bar) {}

现在您可以调用foo()对于 tuple 的两个包装类的实例tuple 的 s 和别名模板秒。您可以以相同的方式为 std::variant 实现

关于c++ - 使用嵌套模板进行模板化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51997488/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com