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.
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.