在我的一个库中,我有以下代码(为简洁起见,进行了剪辑):
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
现在,使用 Linux 上的 GCC 和 Clang,这可以正常工作。但在 Windows 上使用 MSVC 16.8.4 时,我的一个用户得到:
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)"
我不明白实例化如何会导致意外的结果。我也不明白我的一个类名与另一个类名的“名称隐藏”会对模板实例化产生任何影响。
(这大部分归功于@Guillaume Racicot。)
这里的问题是名称查找的时间。
其他编译器,当遇到模板声明时,
region_t
,似乎会寻找先前定义的region_t
;找到memory::region_t
;并对此表示同意。 (如果我错了请纠正我)。
然而,MSVC 执行查找两次:一次是在遇到声明+定义时,然后是在实例化时再次查找 - 两次都使用不同的上下文。所以,第一次,它找到了 memory::region_t
;第二次它找到
memory::managed::region_t
。这真是“意料之外”……MSVC 的这种行为显然是由于其“宽容”编译模式(默认情况下启用)造成的。这有点奇怪,看看在这种情况下它是如何
less宽容的:-(