Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 355
crazypeter Avatar asked Jul 21 '15 13:07

crazypeter


People also ask

What is template argument deduction in C++?

Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.

What is Typename C++?

" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.

What is a deduction guide?

Template deduction guides are patterns associated with a template class that tell the compiler how to translate a set of constructor arguments (and their types) into template parameters for the class. The simplest example is that of std::vector and its constructor that takes an iterator pair.


1 Answers

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) {}
like image 103
Columbo Avatar answered Oct 19 '22 05:10

Columbo