Class 与函数模板特化
Class vs. function template specialization
我最近才从 here 那里了解到 C++ 中的部分模板特化,它完美地解决了我需要一个模板 class 来对指针和非指针表现不同的问题。一个简化的例子是:
// main.cpp
template <typename T>
class C
{
public:
C( const T& t ) : t_( t ) {}
private:
T t_;
};
template <typename T>
class C<T*>
{
public:
C( const T& t ) : t_( new T(t) ) {}
~C() { delete t_; }
private:
T* t_;
};
int main( int argc, char* argv[] )
{
C<int> c1(4);
C<int*> c2(2);
return 0;
}
我想尝试将这个想法扩展到函数,但是 运行 变成了我不明白的编译器错误:
// main.cpp
#include <set>
template <typename T>
std::set<T> makeSet( size_t off )
{
std::set<T> s;
s.insert( T() + T(off) );
return s;
}
template <typename T>
std::set<T*> makeSet<T*>( size_t off )
{
std::set<T*> s;
T* t = new T( T() + T(off) );
s.insert( t );
return s;
}
int main( int argc, char* argv[] )
{
std::set<int> s1 = makeSet<int>(4);
std::set<int*> s2 = makeSet<int*>(2);
delete *(s2.begin());
return 0;
}
.
$ g++ --version && g++ -g ./main.cpp
g++ (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
./main.cpp:13:38: error: non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed
13 | std::set<T*> makeSet<T*>( size_t off )
| ^
./main.cpp: In function ‘int main(int, char**)’:
./main.cpp:23:37: error: call of overloaded ‘makeSet<int>(int)’ is ambiguous
23 | std::set<int> s1 = makeSet<int>(4);
| ^
./main.cpp:5:13: note: candidate: ‘std::set<T> makeSet(size_t) [with T = int; size_t = long unsigned int]’
5 | std::set<T> makeSet( size_t off )
| ^~~~~~~
./main.cpp:13:14: note: candidate: ‘std::set<T*> makeSet(size_t) [with T = int; size_t = long unsigned int]’
13 | std::set<T*> makeSet<T*>( size_t off )
| ^~~~~~~~~~~
./main.cpp:24:38: error: call of overloaded ‘makeSet<int*>(int)’ is ambiguous
24 | std::set<int*> s2 = makeSet<int*>(2);
| ^
./main.cpp:5:13: note: candidate: ‘std::set<T> makeSet(size_t) [with T = int*; size_t = long unsigned int]’
5 | std::set<T> makeSet( size_t off )
| ^~~~~~~
./main.cpp:13:14: note: candidate: ‘std::set<T*> makeSet(size_t) [with T = int*; size_t = long unsigned int]’
13 | std::set<T*> makeSet<T*>( size_t off )
| ^~~~~~~~~~~
我对此有点怀疑,因为它看起来像是试图重载具有不同 return 类型但具有相同参数的函数 - 我知道这在其他方面是非法的,但我认为这是因为这些是模板函数,在调用函数时指定模板类型(如上main()
)将消除歧义。
但我不确定编译器在第 13 行抱怨的是什么:non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed
错误是什么意思?
我想做的事情甚至可以用 C++ 实现吗? IE。是否可以制作一个模板函数,使其对指针和非指针模板类型以及 return 指定类型的 STL 容器表现不同?(答案在 C++ 98、03、 11 和 14?)
您可以尝试这样的操作 (C++17):
template <typename T>
std::set<T> makeSet( size_t off )
{
std::set<T> s;
if constexpr(std::is_pointer_v<T>)
{
using U = std::remove_reference_t<decltype(*std::declval<T>())>;
s.insert(new U( U() + U(off) ));
}
else
{
s.insert( T() + T(off) );
}
return s;
}
what does the non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed
error mean?
让我们看一下有关部分模板专业化的一些文档from cppreference.com:
Allows customizing class [and variable (since C++14)] templates for a given category of template arguments.
class 和变量模板允许部分特化。编译器告诉您,您的模板既不用于 class 变量。因此,不允许偏特化。
编译器消息的一个不太容易混淆的措辞是:不允许函数模板的部分特化。
至于可以做什么,可以用合适的 operator()
声明一个 class 模板。在某些情况下,这与使用函数模板一样好。
我最近才从 here 那里了解到 C++ 中的部分模板特化,它完美地解决了我需要一个模板 class 来对指针和非指针表现不同的问题。一个简化的例子是:
// main.cpp
template <typename T>
class C
{
public:
C( const T& t ) : t_( t ) {}
private:
T t_;
};
template <typename T>
class C<T*>
{
public:
C( const T& t ) : t_( new T(t) ) {}
~C() { delete t_; }
private:
T* t_;
};
int main( int argc, char* argv[] )
{
C<int> c1(4);
C<int*> c2(2);
return 0;
}
我想尝试将这个想法扩展到函数,但是 运行 变成了我不明白的编译器错误:
// main.cpp
#include <set>
template <typename T>
std::set<T> makeSet( size_t off )
{
std::set<T> s;
s.insert( T() + T(off) );
return s;
}
template <typename T>
std::set<T*> makeSet<T*>( size_t off )
{
std::set<T*> s;
T* t = new T( T() + T(off) );
s.insert( t );
return s;
}
int main( int argc, char* argv[] )
{
std::set<int> s1 = makeSet<int>(4);
std::set<int*> s2 = makeSet<int*>(2);
delete *(s2.begin());
return 0;
}
.
$ g++ --version && g++ -g ./main.cpp
g++ (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
./main.cpp:13:38: error: non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed
13 | std::set<T*> makeSet<T*>( size_t off )
| ^
./main.cpp: In function ‘int main(int, char**)’:
./main.cpp:23:37: error: call of overloaded ‘makeSet<int>(int)’ is ambiguous
23 | std::set<int> s1 = makeSet<int>(4);
| ^
./main.cpp:5:13: note: candidate: ‘std::set<T> makeSet(size_t) [with T = int; size_t = long unsigned int]’
5 | std::set<T> makeSet( size_t off )
| ^~~~~~~
./main.cpp:13:14: note: candidate: ‘std::set<T*> makeSet(size_t) [with T = int; size_t = long unsigned int]’
13 | std::set<T*> makeSet<T*>( size_t off )
| ^~~~~~~~~~~
./main.cpp:24:38: error: call of overloaded ‘makeSet<int*>(int)’ is ambiguous
24 | std::set<int*> s2 = makeSet<int*>(2);
| ^
./main.cpp:5:13: note: candidate: ‘std::set<T> makeSet(size_t) [with T = int*; size_t = long unsigned int]’
5 | std::set<T> makeSet( size_t off )
| ^~~~~~~
./main.cpp:13:14: note: candidate: ‘std::set<T*> makeSet(size_t) [with T = int*; size_t = long unsigned int]’
13 | std::set<T*> makeSet<T*>( size_t off )
| ^~~~~~~~~~~
我对此有点怀疑,因为它看起来像是试图重载具有不同 return 类型但具有相同参数的函数 - 我知道这在其他方面是非法的,但我认为这是因为这些是模板函数,在调用函数时指定模板类型(如上main()
)将消除歧义。
但我不确定编译器在第 13 行抱怨的是什么:non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed
错误是什么意思?
我想做的事情甚至可以用 C++ 实现吗? IE。是否可以制作一个模板函数,使其对指针和非指针模板类型以及 return 指定类型的 STL 容器表现不同?(答案在 C++ 98、03、 11 和 14?)
您可以尝试这样的操作 (C++17):
template <typename T>
std::set<T> makeSet( size_t off )
{
std::set<T> s;
if constexpr(std::is_pointer_v<T>)
{
using U = std::remove_reference_t<decltype(*std::declval<T>())>;
s.insert(new U( U() + U(off) ));
}
else
{
s.insert( T() + T(off) );
}
return s;
}
what does the
non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed
error mean?
让我们看一下有关部分模板专业化的一些文档from cppreference.com:
Allows customizing class [and variable (since C++14)] templates for a given category of template arguments.
class 和变量模板允许部分特化。编译器告诉您,您的模板既不用于 class 变量。因此,不允许偏特化。
编译器消息的一个不太容易混淆的措辞是:不允许函数模板的部分特化。
至于可以做什么,可以用合适的 operator()
声明一个 class 模板。在某些情况下,这与使用函数模板一样好。