Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is template disambiguator needed in this case?

I'm trying to understand why I need to use a template disambiguator in some openCL code.

EDIT: Here's a minimal reproducing case:

//test.hpp
#include <iostream>
#include <vector>
#include "cl.hpp"

template <typename T>
class Foo {
    public:
    std::vector<cl::Platform> platforms;
    std::vector<cl::Device> devices;    
    Foo();   
    void bar();
};

template<typename T>
Foo<T>::Foo() {      
    cl::Platform::get(&platforms);
    platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
}

template<typename T>
void Foo<T>::bar() {
    // Fails to compile:  error: expected expression
    //std::cout << devices[0].getInfo<CL_DEVICE_NAME>() << std::endl;
    // Works
    std::cout << devices[0].template getInfo<CL_DEVICE_NAME>() << std::endl;
    // Also works
    cl::Device &mydevice = devices[0];
    std::cout << mydevice.getInfo<CL_DEVICE_NAME>() << std::endl;

}

and the source file:

//test.cpp
#include "test.hpp"

int main() {
    Foo<double> foo = Foo<double>();    
    foo.bar();    
    return 0;
}

What is different about the reference that makes a template disambiguator unnecessary? I"m trying to understand where the ambiguity is here. (Also, I know I'm not using the templated variable in my class, this is just a minimal case that reproduced the issue.)

like image 492
Rob Falck Avatar asked Nov 10 '22 10:11

Rob Falck


1 Answers

First of all, this is just a typical issue in general in template code. The issue is that because, at the point of parsing the nature of getInfo is unknown (is it a function template or a regular member variable ?) the parser does not know whether to interpret < as less-than or as the start of specifying template parameters.

Thus the rule in §14.2 [temp.names]/4, of which the example is:

template<class T> void f(T* p) {
    T* p1 = p->alloc<200>();          // ill-formed: < means less than
    T* p2 = p->template alloc<200>(); // OK: < starts template argument list
    T::adjust<100>();                 // ill-formed: < means less than
    T::template adjust<100>();        // OK: < starts template argument list
}

Now, in your case this seems a bit silly I fathom, because it's a Device right ? Yes, in your case. But what of:

template <typename T> struct Wrecker { using type = std::vector<Device>; };
template <> struct Wrecker<double> { using type = std::vector<Other>; };

template <typename T>
struct Foo {
    using Devices = typename Wrecker<T>::type;
    Devices devices;

    void bar();
};

So, yes, the rule is not as precise as it could be. It could delve even further into the fray and check whether the actual type can be deduced...

... but do you realize that, as it is, the simple fact of allowing you to elide template in some circumstances (non-dependent situations) already requires one of the worst compiler hacks ever ? The traditional pipeline: tokenization -> parsing -> semantic analysis has to be completely twisted in C++ to allow feedback of semantic analysis during the parsing phase to automatically disambiguate that foo<4>() is a template call.

Personally, my recommendation would have been to mandate template systematically. It would have saved a lot of troubles.

like image 185
Matthieu M. Avatar answered Nov 15 '22 06:11

Matthieu M.