问题描述
我不明白为什么下面的代码不能编译。编译器给出的错误消息也没有那么有用。
工作示例:
#include <string>
#include <type_traits>
template <typename T>
struct TIteratorValue {
using Type = typename T::Type;
};
template <typename T>
struct TIteratorValue<T *> {
using Type = T;
};
template <typename T>
using IteratorValue = typename TIteratorValue<T>::Type;
template <typename T>
struct Test {
template <typename V,std::enable_if_t<std::is_constructible_v<T,V>,int> = 0>
Test(std::initializer_list<V> const list,size_t const x = 0)
: Test(list.begin(),list.end(),x) {}
template <typename I,IteratorValue<I>>,int> = 0>
// Does not compile!
Test(I begin,I const end,size_t const x = 0) {}
// Compiles!
//Test(I begin,size_t const x) {}
};
int
main() {
Test<std::string> test({ "a","b","c" },10);
return 0;
}
Clang 的错误信息:
C:\Users\joaom\DropBox\++A\so\weird_overloading.cpp:6:24: error: type 'int' cannot be used prior to '::' because it has no members
using Type = typename T::Type;
^
C:\Users\joaom\DropBox\++A\so\weird_overloading.cpp:15:1: note: in instantiation of template class 'TIteratorValue<int>' requested here
using IteratorValue = typename TIteratorValue<T>::Type;
^
C:\Users\joaom\DropBox\++A\so\weird_overloading.cpp:25:50: note: in instantiation of template type alias 'IteratorValue' requested here
std::enable_if_t<std::is_constructible_v<T,int> = 0>
^
C:\Users\joaom\DropBox\++A\so\weird_overloading.cpp:27:2: note: while substituting prior template arguments into non-type template parameter
[with I = int]
Test(I begin,size_t const x = 0) {}
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\joaom\DropBox\++A\so\weird_overloading.cpp:35:20: note: while substituting deduced template arguments into function template 'Test'
[with I = int,$1 = (no value)]
Test<std::string> test({ "a",10);
唯一的 int
是参数 x
,但我看不出它如何影响代码。
Visual Studio 也给了我同样的错误。
解决方法
template <typename I,std::enable_if_t<std::is_constructible_v<T,IteratorValue<I>>,int> = 0>
// Does not compile!
Test(I begin,I const end,size_t const x = 0) {}
// Compiles!
//Test(I begin,size_t const x) {}
两个如果模板被实例化,这两个函数将不会编译。
由于您的 main
函数试图从 2 个参数构造一个 Test
,因此向第三个参数添加默认值仅意味着应该考虑该函数。它允许实例化模板。
我还是不明白为什么下面的代码不能编译。
您正在定义 IteratorValue<I>
(因此是 I::type
)之前检查 I
是否是迭代器。
使用已经定义的 std::iterator_traits
来解决这个问题。
// Formatted for clarity
template <typename I,std::enable_if_t<
std::is_constructible_v<
T,typename std::iterator_traits<I>::value_type
>,int
> = 0>