In a library of mine, I have the following bit of code (snipped for brevity):
namespace memory {
namespace managed {
namespace detail {
template <typename T>
inline T get_scalar_range_attribute(
region_t region,
cudaMemRangeAttribute attribute)
{ /* snip */ }
} // namespace detail
struct region_t : public memory::region_t {
// snip
bool is_read_mostly() const
{
return detail::get_scalar_range_attribute<bool>(
*this, cudaMemRangeAttributeReadMostly);
}
// snip
}
} // namespace managed
} // namespace memory
Now, with GCC and Clang on Linux, this works fine. But with MSVC 16.8.4 on Windows, a user of mine gets:
error : template instantiation resulted in unexpected function type of "__nv_bool
(cuda::memory::managed::region_t, cudaMemRangeAttribute)" (the meaning of a name
may have changed since the template declaration -- the type of the template is "T
(cuda::memory::region_t, cudaMemRangeAttribute)"
I don't understand how an instantiation can result in something unexpected, ever. I also don't see how my "name hiding" of one class name with another should have any effect on the template instantiation.
(Credit goes to @Guillaume Racicot for most of this.)
The issue here is the timing of name lookup.
Other compilers, when encountering the template declaration, region_t
, seem to look for previously-defined region_t
's; find memory::region_t
; and are ok with that. (Correct me if I'm wrong).
MSVC, however, performs the lookup twice: Once when encountering the declaration+definition, then again upon instantiation - with different contexts both times. So, the first time, it finds memory::region_t
; and the second time it finds memory::managed::region_t
. This is "unexpected"...
This behavior of MSVC is apparently due to its "permissive" compilation mode (which is enabled by default). It's a bit weird, seeing how it is less permissive in this case :-(