为什么不能推导出这个metametafunction的模板参数呢?

Why can't this metametafunction's template parameter be deduced?

我有以下 wrapper-maker 元元功能:

template <class ToWrap>
struct wrapper_maker
{
    template <bool>
    struct wrapper
    {
        wrapper(ToWrap& a) : a(a) { }
        ToWrap& a;
    };
};

我想在这个模板函数中使用它foo:

template <class ToWrap>
void foo(typename wrapper_maker<ToWrap>::template wrapper<true>& wrapped)
{
    cout << "foo" << endl;
}

注意:用例是 foo 已经存在不同的重载,但如果对象是 wrapper_maker<ToWrap>::wrapper<bool> 实例,我希望调用这个特定的重载。

然而,当我编写一个调用 foo 的函数时:

template <class ToWrap>
void call_foo(ToWrap& o)
{
    typedef typename wrapper_maker<ToWrap>::template wrapper<true> wrapped_t;
    wrapped_t wrapped(o);
    foo(wrapped);
}

这样使用它:

int to_wrap = 5;
call_foo(to_wrap);

我收到这个错误:

prog.cpp: In instantiation of 'void call_foo(ToWrap&) [with ToWrap = int]':
prog.cpp:32:18:   required from here
prog.cpp:27:16: error: no matching function for call to 'foo(wrapped_t&)'
     foo(wrapped);
                ^
prog.cpp:27:16: note: candidate is:
prog.cpp:17:6: note: template<class ToWrap> void foo(typename wrapper_maker<ToWrap>::wrapper<true>&)
 void foo(typename wrapper_maker<ToWrap>::template wrapper<true>& wrapped)
      ^
prog.cpp:17:6: note:   template argument deduction/substitution failed:
prog.cpp:27:16: note:   couldn't deduce template parameter 'ToWrap'
     foo(wrapped);

这是为什么?

编辑:此外,是否有任何方法可以定义 foo 的特化,它将在 wrapper_maker<T>::wrapper<W> 的实例上调用,对于任何可能的 T,而不必指定TW 在呼叫站点?

这个:

template <class ToWrap>
void foo(typename wrapper_maker<ToWrap>::template wrapper<true>& wrapped)

是非推导上下文。具体来说,列表中的第一个来自 [temp.deduct.type]4/5:

If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

The non-deduced contexts are:
(5.1) — The nested-name-specifier of a type that was specified using a qualified-id.

您需要显式传入 ToWrap 才能使其生效。

让我再举一个例子来说明为什么会这样。假设我们有:

template <typename T> struct some_fn;
template <> struct some_fn<A> { using type = int; };
template <> struct some_fn<B> { using type = int; };

template <typename T>
void foo (typename some_fn<T>::type);

foo(0); // what should T be?

一般来说,为了实现这一点,编译器必须知道 some_fn 的每一种可能的特化 - 即使只有一个 some_fn<T>::typeint

Further, is there any way to define a specialization of foo that will get called on instances of wrapper_maker<T>::wrapper<W>, for any possible T, without having to specify either T or W at the call-site?

一般来说,不会,原因与上述相同。但是,您可以将其他信息添加到 wrapper:

template <class ToWrap>
struct wrapper_maker
{
    template <bool b>
    struct wrapper
    {
        static constexpr bool value = b;
        using to_wrap = ToWrap;

        // etc.
    };
};

template <typename WrapperT>
void foo(WrapperT& wrapped) {
    // typename WrapperT::to_wrap is your T
    // WrappedT::value is your W
}