Search code examples
c++c++14autodecltypetype-deduction

Type deducted of method definition doesn't match declaration


I tried to use some of the new features of C++11/14 and came across a nasty thing with type deduction of class methods within their defition.

The scenario:

// in header foo.hpp
class MyClass {
    T foo();
}

//in source foo.cpp
auto MyClass::foo() {
    return ... //something that returns T!
}

For T = cl_uint (OpenCL) this does not work and the compiler outputs the following error message:

src/device.cpp:9:7: error: prototype for ‘auto CL::Device::addressBits() const’ does not match any in class ‘CL::Device’

and

src/device.hpp:31:11: error: candidate is: cl_uint CL::Device::addressBits() const

This behaves equally with the newest versions of GCC and Clang. The concrete example is as follows:

// in the .hpp
namespace CL {
    class Device : public Object<cl_device_id, cl_device_info, DeviceFunctions> {
    public:
        Device(cl_device_id id);

        cl_uint addressBits() const;

        // much more stuff ... (not of interest atm)
    }
}

// in the .cpp
namespace CL {
    auto Device::addressBits() const {
        return getInfo<cl_uint>(CL_DEVICE_ADDRESS_BITS);
    }
}

// in object.hpp => inherited by device
namespace CL {
    template<typename U, typename InfoIdType, typename Functions>
    class Object {
    protected:
        template<typename T>
        T getInfo(InfoIdType info_id) const {
            auto error = cl_int{CL_INVALID_VALUE};
            auto info  = T{};
            error = Functions::get_info(m_id, info_id, sizeof(T), &info, nullptr);
            return (error == CL_SUCCESS) ? info : T{};
        }
    }
}

I am well aware that this problem doesn't lead to anything terrible nor isn't it fixable by leaving out type deduction for this scenario. However, as I am trying to adopt the new and cool C++11/14 features I'd like to understand why this in particular does not work as I thought it would.


Solution

  • You can simplify all that code to this:

    struct A {
      int func();
    };
    
    auto A::func() { return 0; }
    

    This is not valid, a function that is declared with a placeholder type must use the placeholder in all declarations:

    [decl.spec.auto]/13:

    Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type.