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

时间:2015-06-10 19:05:54

标签: c++ templates template-meta-programming

我有以下包装器制造商metametafunction:

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的实例,而无需指定任何T W在呼叫站点1}}或Sub ExpirationYeartoColors() Dim num As Integer, lr As Long, r As Long

1 个答案:

答案 0 :(得分:3)

此:

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

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

  

如果模板参数仅在非推导中使用   上下文并没有明确指定,模板参数推断失败。

     

未推断的背景是:
  (5.1) - 使用 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>::type只有int wrapper_maker<T>::wrapper<W>

  

此外,有没有办法定义foo的特化,可以在T的实例上调用任何可能的T,而不必指定W或{{ 1}}在呼叫现场?

总的来说,不,出于上述相同的原因。但是,您只需向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
}