我正在设计一个类模板Monad
,它由模板类型参数化。例如,可以有Monad<std::vector>
,Monad<std::shared_ptr>
等
我有这个实用程序struct
可用于提取较高级别类型的容器类型(例如从std::vector
中提取std::vector<int>
):
template<typename>
struct FType;
template<typename A>
struct FType<std::vector<A>> {
template<typename B>
using type = std::vector<B>;
};
// FType<std::vector<int>>::type == std::vector
现在为Monad
:
template<template <typename...> class F>
struct Monad;
template<>
struct Monad<std::vector> {
/*
* Example parameters:
* FA: std::vector<int>
* F: std::vector
* M: Monad<std::vector>
*/
template<typename FA,
template <typename...> class F = FType<FA>::template type,
typename M = Monad<F>>
static void foo(const FA &)
{
M::bark();
}
static void bark()
{
std::cout << "Woof!\n";
}
};
我试图Monad::foo
自动推断其模板参数。所以不要这样做:
std::vector<int> v{1, 2, 3};
// This works
Monad<std::vector>::foo<
std::vector<int>, // FA
std::vector, // F
Monad<std::vector> // M
>(v);
// This also works
Monad<std::vector>::foo<
std::vector<int>, // FA
std::vector // F
>(v);
我希望能够做到:
std::vector<int> v{1, 2, 3};
// This does not compile
Monad<std::vector>::foo(v);
// Neither does this
Monad<std::vector>::foo<
std::vector<int> // FA
>(v);
我得到的错误(对于两个未编译的例子)是:
error: implicit instantiation of undefined template 'Monad<type>'
M::bark();
^
template is declared here
struct Monad;
^
error: incomplete definition of type 'Monad<type>'
M::bark();
~^~
我该如何解决这个问题?
更新:正如Sam指出的那样,std::vector
,FType<std::vector<Something>>::type
和FType<std::vector<SomethingElse>>::type
都是不同的! (虽然对于特定的A
,std::is_same
表示std::vector<A>
,FType<std::vector<Something>>::type<A>
和FType<std::vector<SomethingElse>>::type<A>
相同。)如果我专注Monad<FType<std::vector<int>>::type>
,然后事情就结束了......但显然这是不可取的......有没有其他方法可以实现FType
?
更新2:将FType
更改为:
template<typename... A>
struct FType<std::vector<A...>> {
template<typename... B>
using type = std::vector<B...>;
};
没有效果。
答案 0 :(得分:2)
问题是当您为std::vector
明确提供F
时,F
实际上是std::vector
。但是,当您允许推断它时,它会被推断为FType<A>::type
- 不是 std::vector
。它是可以推断的,但它不一样。
你实际上并不......对于这个特殊问题需要这些额外的机器吗?您可以将foo
的参数推断为模板模板的实例:
template <template <typename...> class F, typename... Args>
static void foo(F<Args...> const& ) {
using M = Monad<F>;
M::bark();
}
更一般地说,您只需一步即可从FA
转到monad:
template <class FA>
struct as_monad;
template <class FA>
using as_monad_t = typename as_monad<FA>::type;
template <template <typename...> class F, typename... Args>
struct as_monad<F<Args...>> {
using type = Monad<F>;
};
然后:
template <class FA>
static void foo(FA const& ) {
using M = as_monad_t<FA>;
M::bark();
}