I'm designing a class template Monad
, which is parameterized by a template type. For example, there can be Monad<std::vector>
, Monad<std::shared_ptr>
, etc.
I have this utility struct
that can be used to extract the container type of a higher-kinded type (e.g. extract std::vector
from a 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
Now for 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";
}
};
I'm trying to have Monad::foo
automatically infer its template parameters. So instead of doing:
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);
I want to be able to do:
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);
The error I got (for both not-compiling examples) was:
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();
~^~
How can I solve this?
UPDATE: As Sam has pointed out, std::vector
, FType<std::vector<Something>>::type
, and FType<std::vector<SomethingElse>>::type
are all different! (Although for a specific A
, std::is_same
shows that std::vector<A>
, FType<std::vector<Something>>::type<A>
, and FType<std::vector<SomethingElse>>::type<A>
are the same.) If I specialize Monad<FType<std::vector<int>>::type>
, then things work out...but clearly this is not desirable... Is there any other way to implement FType
?
UPDATE 2: Changing FType
to this:
template<typename... A>
struct FType<std::vector<A...>> {
template<typename... B>
using type = std::vector<B...>;
};
has no effect.