gpt4 book ai didi

c++ - 专门化具有 decltype 尾随返回类型的函数模板

转载 作者:行者123 更新时间:2023-11-30 01:18:55 24 4
gpt4 key购买 nike

在 C++11 中,如何使用 decltype 专门化声明为“复杂”尾随返回类型的函数模板?以下在 GCC 中有效,但在 VC2013 中产生“error C2912: explicit specialization 'int f(void)' is not a specialization of a function template”:

#include <iostream>

int myint() { return 1; }

template<class T>
auto f() -> decltype(myint()) // this seems to cause problems
{
std::cout << "general\n";
return 1;
}

template <>
auto f<double>() -> decltype(myint())
{
std::cout << "special\n";
return 2;
}

int main()
{
f<int>();
f<double>(); // compiler error in VC, but not in GCC
}

我说“复杂”是因为缺乏技术上精确的词,因为我不确定是什么造成了差异。例如,以下 decltype,使用不依赖于任何函数结果类型的内置操作,可以很好地与模板特化一起工作:

自动 f() -> decltype(1 + 1)

所以,我的问题(都相互关联):

  1. 我的代码是正确的 C++11 吗?
  2. 这是 VC 的错误吗?
  3. 如果这种专门化不起作用,我怎么能专门化 std::begin 和 std::end(并因此提供基于范围的 for 循环)用于不可更改的遗留容器类?

最佳答案

Is my code correct C++11?

在我看来是正确的。此外,使用 gcc 和使用 -Wall -Wextra 的 clang 都可以干净地编译。

Is this a VC bug?

很有可能。 VC 在这方面臭名昭著,例如 What exactly is "broken" with Microsoft Visual C++'s two-phase template instantiation?google msvc two-phase lookup

How could I ever specialise std::begin and std::end (and thus provide range-based for loops) for an unchangeable legacy container class if this kind of specialization does not work?

对于您提供的代码,解决方法是使用 typedef:

#include <iostream>

int myint() { return 1; }

typedef decltype(myint()) return_type;

template<class T>
return_type f()
{
std::cout << "general\n";
return 1;
}

template <>
return_type f<double>()
{
std::cout << "special\n";
return 2;
}

int main()
{
f<int>();
f<double>();
}

所有三个主流编译器(gcc、clang、vs)似乎都对这段代码感到满意。


更新:

How could I ever specialise std::begin and std::end (and thus provide range-based for loops) for an unchangeable legacy container class if this kind of specialization does not work?
[And from the comments:] I thought specialising std::begin and std::end was always the best approach.

经过深思熟虑,专门化 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 { 并关闭 })但我更喜欢将我的实现放入我自己的命名空间。

另见

关于c++ - 专门化具有 decltype 尾随返回类型的函数模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21796388/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com