C++ 使用嵌套模板创建模板

C++ 使用嵌套模板创建模板,c++,templates,type-alias,C++,Templates,Type Alias,下面的代码不起作用,因为推断的模板参数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 tes

下面的代码不起作用,因为推断的模板参数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>());
}
更多信息 我在使用C++17的
std::variant
的同时,还使用了对单个类型通用的别名类型,我更愿意使用
语句声明这些类型,而不是为每个类型创建包装类。大概是这样的:

// Assuming Plus, Minus, etc all exist
template <typename T>
using Operation = std::variant<Plus<T>, Minus<T>, Times<T>>;
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);
};
根据下面怀疑论者的回答,我认为类型别名可能不是解决问题的方法,相反,我必须引入小的包装类——除非有一种SFINAE方法可以实现这一点


这个库主要是一种好奇心,也是我探索一些更高级模板概念的一种方法-谢谢你的帮助

因此,在我们开始挖掘一些基于SFINAE的骗局之前,首先尝试一下:

别名模板从不通过模板参数推断推断出来

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

#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>());
}
现在,您可以为
tuple
s的包装类和
tuple
s的别名模板的实例调用
foo()
。您也可以用同样的方式为std::variant实现。

使用:

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>()); }
您希望编译器如何从
tuple
中推断出它来自哪个别名

我们可能有

template <typename T> using Bar = std::tuple<int, std::string>;
template <typename T> using Bar2 = std::tuple<some_trait<T>::type, some_trait<T>::type2>;
// ...
使用Bar=std::tuple的模板;
使用Bar2=std::tuple的模板;
// ...
一种可能的解决方法可能是:

template <typename T, typename U>
Foo<U> fmap(std::function<U(T)> f, Foo<T> value)
{
    return Foo<U>(std::get<0>(value), f(std::get<1>(value)));   
}
模板
Foo-fmap(标准::函数f,Foo值)
{
返回Foo(std::get(value),f(std::get(value));
}
使用调用语法:

fmap(fn, Foo<int>(42, 7));
fmap(fn,Foo(42,7));

我更愿意这样做——我正在编写一个基于Haskell函子的小型函子库。“我将在我的原始帖子中添加更多的上下文。@泰勒添加了一个编辑,以保留完整的要求,因为我已经从您的问题中收集到了到目前为止的内容。从你的角度让我知道它的立场。谢谢你深入了解。我最终选择了包装器类,因为我认为
使用
方法可能会导致更多问题。这将是很好的,如果C++提供了相当于Haskell的<代码> NeXyTys/COD>——<>代码>使用< /CODE >的简单性,但它也创建了一种新类型,可以用编译器代替别名进行检查。虽然我现在明白了为什么会是这样。
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) {}
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>()); }
void test() { foo(std::tuple<int, std::string>()); }
template <typename T> using Bar = std::tuple<int, std::string>;
template <typename T> using Bar2 = std::tuple<some_trait<T>::type, some_trait<T>::type2>;
// ...
template <typename T, typename U>
Foo<U> fmap(std::function<U(T)> f, Foo<T> value)
{
    return Foo<U>(std::get<0>(value), f(std::get<1>(value)));   
}
fmap(fn, Foo<int>(42, 7));