How to make C++ find templated function header whe

2019-07-02 05:09发布

I'm trying to build a templated C++ function that accepts, as its argument, a pointer to an object of an inner class. Here is a reduced version of the class structure involved, similar to a typical linked-list or tree class:

template <typename T>
struct Outer
{
  struct Inner
  {
    T val;
    Inner (T v) : val(v) { }
  };

  Inner* ptr;

  Outer(T val)
  {
    ptr = new Inner(val);
  }
};

I've made them structs to exclude any access control issues and removed some extraneous instance variables. With that class structure in mind, here are three functions, the first two of which aren't quite what I want:

template <typename T>
void testOuter (const Outer<T>& obj)
{
  cout << obj.ptr->val << endl;
}

void testInnerInt (const Outer<int>::Inner* p)
{
  cout << p->val << endl;
}

template <typename T>
void testInnerTemplated (const typename Outer<T>::Inner* p)
{
  cout << p->val << endl;
}

This third function is basically what I want, header-wise (it's intended as a helper function in a larger body of code, of course), but it doesn't work. If I compile and run the following main function:

int main()
{
  Outer<int> foo(5);

  cout << foo.ptr->val << endl;
  testInnerInt(foo.ptr);
  //testInnerTemplated(foo.ptr);
  testOuter(foo);
}

it runs just fine (printing 5 three times), but if I uncomment the line with the call to testInnerTemplated, I get a compiler error saying no matching function for call to ‘testInnerTemplated(Outer<int>::Inner*&)’ (in g++ 4.9.1). I guess it's a problem with the template lookup or matching, but how can I tell the compiler how to resolve it?

2条回答
聊天终结者
2楼-- · 2019-07-02 05:22
template <typename T>
void testInnerTemplated(const typename Outer<T>::Inner*);

The compiler can't deduce T through template argument deduction because this is a non-deduced context as defined in the standard:

The nondeduced contexts are:

The nested-name-specifier of a type that was specified using a qualified-id. A type that is a template-id in which one or more of the template-arguments is an expression that references a template-parameter.

When a type name is specified in a way that includes a nondeduced context, all of the types that comprise that type name are also nondeduced. However, a compound type can include both deduced and nondeduced types. [Example: If a type is specified as A<T>::B<T2>, both T and T2 are nondeduced. Likewise, if a type is specified as A<I+J>::X<T>, I, J, and T are nondeduced. If a type is specified as void f(typename A<T>::B, A<T>), the T in A<T>::B is nondeduced but the T in A<T> is deduced. ]

查看更多
\"骚年 ilove
3楼-- · 2019-07-02 05:27

If you wish to recover the type information from Outer<> from within Inner, you can use traits.

template <typename T>
struct Outer
{
    typedef T TypeParam;

    struct Inner
    {
        typedef Outer<T> InnerOuter;
        T val;
        Inner (T v) : val(v) {}
    };

    Inner *ptr;

    Outer (T val) : ptr(new Inner(val)) {}
};

Now define a more generic testInnerTemplated, but it uses traits to recover the type information passed to Outer<>.

template <typename T>
void testInnerTemplated (const T * p)
{
  typename T::InnerOuter::TypeParam val = p->val;
  std::cout << val << std::endl;
}
查看更多
登录 后发表回答