模板特化的隐式实例化

时间:2016-04-07 12:33:30

标签: c++ templates

我正在设计一个类模板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::vectorFType<std::vector<Something>>::typeFType<std::vector<SomethingElse>>::type都是不同的! (虽然对于特定的Astd::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...>;
};

没有效果。

1 个答案:

答案 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();
}