专用具有decltype追踪返回类型的函数模板
在C ++ 11中,我怎样才能专门化一个使用decltype用“复杂”尾随返回类型声明的函数模板? 下面的代码在GCC中工作,但在VC2013中产生“错误C2912:显式专用化”int f(void)'不是函数模板的专门化“
#include <iostream>
int myint() { return 1; }
template<class T>
auto f() -> decltype(myint()) // this seems to cause problems
{
std::cout << "generaln";
return 1;
}
template <>
auto f<double>() -> decltype(myint())
{
std::cout << "specialn";
return 2;
}
int main()
{
f<int>();
f<double>(); // compiler error in VC, but not in GCC
}
我说缺乏一个技术上精确的词“复杂”,因为我不知道是什么造成了差异。 例如,以下decltype使用不依赖于任何函数结果类型的内置操作,可以很好地处理模板特化:
auto f() - > decltype(1 + 1)
所以,我的问题(所有相关的):
我的代码是否正确C ++ 11?
看起来对我来说是正确的。 另外,用gcc和clang用-Wall -Wextra
编译干净。
这是一个VC错误?
最有可能的。 在这方面,VC是臭名昭着的,例如,看看Microsoft Visual C ++的两阶段模板实例是什么“破碎”? 或谷歌msvc两阶段查找。
如果这种专门化不起作用,我怎么能专门化std :: begin和std :: end(并且因此提供基于范围的for循环)一个不可改变的遗留容器类?
对于您提供的代码,解决方法是使用typedef:
#include <iostream>
int myint() { return 1; }
typedef decltype(myint()) return_type;
template<class T>
return_type f()
{
std::cout << "generaln";
return 1;
}
template <>
return_type f<double>()
{
std::cout << "specialn";
return 2;
}
int main()
{
f<int>();
f<double>();
}
所有三种主流编译器(gcc,clang,vs)似乎都对此代码感到满意。
更新:
如果这种专门化不起作用,我怎么能专门化std::begin
和std::end
(并且因此提供基于范围的for循环)一个不可改变的遗留容器类?
[并从评论:]我认为专门化std::begin
和std::end
总是最好的方法。
给了它一些想法后,专门化std::begin()
和std::end()
将是我最后的手段。 我的第一个尝试是提供成员begin()
和end()
函数; 不幸的是,它不适合你,因为你不能修改相应的代码。 然后,我的第二次尝试将是在我自己的名字空间中提供免费的功能:
#include <iostream>
#include <initializer_list>
#include <vector>
namespace my_namespace {
template <typename T> class my_container;
template <typename T> T* begin(my_container<T>& c);
template <typename T> T* end(my_container<T>& c);
template <typename T>
class my_container {
public:
explicit my_container(std::initializer_list<T> list) : v(list) { }
friend T* begin<>(my_container& c);
friend T* end<>(my_container& c);
private:
std::vector<T> v;
};
template <typename T>
T* begin(my_container<T>& c) {
return c.v.data();
}
template <typename T>
T* end(my_container<T>& c) {
return c.v.data()+c.v.size();
}
}
int main() {
my_namespace::my_container<int> c{1, 2, 3};
for (int i : c)
std::cout << i << 'n';
}
如果你能够专门化容器的std::begin()
和std::end()
,这种方法必须工作。 如果你在全局命名空间中执行它(也就是说,你只是省略namespace my_namespace {
和关闭}
),它也可以工作,但我更喜欢将我的实现放到我自己的命名空间中。
也可以看看
如何使我的自定义类型与“基于范围的循环”一起工作?
为什么没有范围 - 找到std :: istream_iterator的开始和结束的重载?
上一篇: Specialize function template with decltype trailing return type
下一篇: C++11 compiler error when using decltype(var) followed by internal type of "var"