crazypeter
crazypeter

Reputation: 1449

Dependent Types: Template argument deduction failed

In my code I use a templated image class Image<T> in combination with std::shared_ptr. These image pointers are supposed to be passed to various image processing functions, some of which are independent of the image type. Consider the following definition of Image<T>, and two processing functions function1() and function2().

#include <memory>

template <typename T>
struct Image
{
    typedef std::shared_ptr<Image<T>> Ptr;
};

template <typename T>
void function1 (typename Image<T>::Ptr image) {}

template <typename T>
void function2 (std::shared_ptr<Image<T>> image) {}

While function1() and function2() effectively have the same signature, function1() is easier to read and hides the details of how the pointer is realized. However, I am having trouble calling function1() without explicitly specifying the template type. Consider the following code:

int main (void)
{
    Image<int>::Ptr image = std::make_shared<Image<int>>();
    function1(image);       // Does NOT compile
    function1<int>(image);  // Does compile
    function2(image);       // Does compile
    return 0;
}

Where the first call leads to the compile error:

example.cc: In function 'int main()':
example.cc:18:19: error: no matching function for call to 'function1(MyClass<int>::Ptr&)'
example.cc:18:19: note: candidate is:
example.cc:10:6: note: template<class T> void function1(typename MyClass<T>::Ptr)
example.cc:10:6: note:   template argument deduction/substitution failed:
example.cc:18:19: note:   couldn't deduce template parameter 'T'

My question is the following: Is it possible to use the signature of function1() without having to manually specify the template argument? What is causing the compiler error?

I suspect the problem is caused by the fact that Image<T>::Ptr is a dependent type. Thus the compiler cannot know the exact definition of this field at compile time. Is it possible to tell the compiler there will be no specializations of this field, in the spirit of the typename keyword which tells the compiler that a field is a type?

Upvotes: 10

Views: 562

Answers (1)

Columbo
Columbo

Reputation: 60999

What is causing the compiler error?

You're (solely) using T in a non-deduced context: nested-name-specifiers. That is, you put T inside a name that merely specifies where the type lies within. The compiler cannot understand your actual intention and would have to try a lot of T's.

Is it possible to use the signature of function1() without having to manually specify the template argument?

Not really. If you want a more concise way of referring to a smart pointer to an Image, you can use an alias template though:

template <typename T>
using ImagePtr = std::shared_ptr<Image<T>>;

And write function1 thusly:

template <typename U>
void function1(ImagePtr<U> p) {}

Upvotes: 9

Related Questions