Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么模板专门化不能更改返回类型?_C++_Templates - Fatal编程技术网

C++ 为什么模板专门化不能更改返回类型?

C++ 为什么模板专门化不能更改返回类型?,c++,templates,C++,Templates,阅读之后,我不得不再次意识到我对模板的了解是多么的少。我可以理解,像这样的模板专门化 // A template <typename T> void foo(T x){} template <> void foo<double>(int x){} (与上述错误类似)。实际上,我手头没有任何特定的用例,但我仍然对如何根据T选择返回类型感兴趣。作为一种解决方法,我发现: // C template <typename T> struct foo {

阅读之后,我不得不再次意识到我对模板的了解是多么的少。我可以理解,像这样的模板专门化

// A
template <typename T> void foo(T x){}
template <> void foo<double>(int x){}
(与上述错误类似)。实际上,我手头没有任何特定的用例,但我仍然对如何根据
T
选择返回类型感兴趣。作为一种解决方法,我发现:

// C 
template <typename T> struct foo { static int moo(T x){return x;} };
template <> struct foo<double> { static double moo(double x){return x;} };
/C
模板结构foo{static int moo(tx){return x;}};
模板结构foo{static double moo(double x){return x;}};
因此,可以根据
T
选择返回类型。然而,我仍然感到困惑


无法执行
B
的原因是什么?

实际上,您可以通过使用返回类型的模板参数或traits类来解决此问题。
例如:

#include<type_traits>

template<typename T>
T f() { return T{}; }

template<typename>
struct Traits;

template<>
struct Traits<int> {
    using ReturnType = char;
};

template<>
struct Traits<char> {
    using ReturnType = int;
};

template<typename T>
typename Traits<T>::ReturnType g() { return T{}; }

int main() {
    static_assert(std::is_same<decltype(f<int>()), int>::value, "!");
    static_assert(std::is_same<decltype(f<double>()), double>::value, "!");
    static_assert(std::is_same<decltype(g<int>()), char>::value, "!");
    static_assert(std::is_same<decltype(g<char>()), int>::value, "!");
}
#包括
模板
tf(){返回T{};}
模板
结构特征;
模板
结构特征{
使用ReturnType=char;
};
模板
结构特征{
使用ReturnType=int;
};
模板
typename Traits::ReturnType g(){return T{};}
int main(){
静态断言(std::is_same::value,“!”;
静态断言(std::is_same::value,“!”;
静态断言(std::is_same::value,“!”;
静态断言(std::is_same::value,“!”;
}
g
的情况下,如果推断出参数,则会发现两个显然相同的调用具有不同的返回类型

也就是说,专门化不允许用户更改函数的声明。

这就是为什么必须使用这样一个定义,才能为不同的模板参数提供不同的返回类型。

即使很奇怪,也可能有

template <typename T>
void foo(int);

template <typename T>
char foo(int);
模板
void foo(int);
模板
查富(国际);

所以你的专业化是不明确的。

1。默认模板参数 您的案例“C”可以使用默认模板参数轻松解决:

template<typename T, typename U = int>
U foo(T x) {
    return x;
}

template<>
double foo<double, double>(double x) {
    return x;
}
2.类型图 另一种方法更丑陋,但更普遍。它将要求您在一个位置枚举所有可能的返回类型,允许您根据模板参数类型选择这些返回类型中的任何一种。该解决方案的关键在于编译时类型映射。可以使用pair、tuple和
tuple\u元素
s以各种方式实现它,但让我们停止使用最简单的实现:

struct last_key{};
struct last_value{};

template<typename key, typename k = last_key, typename v = last_value, typename ...pairs>
struct type_map {
    static_assert(sizeof...(pairs) % 2 == 0, "Last key does not have a value");
    using type = typename std::conditional<std::is_same<key, k>::value,
        v,
        typename type_map<key, pairs...>::type>::type;
};

template<typename key>
struct type_map<key> {
    using type = int;
};
最后,您的示例案例“C”将通过唯一的
foo
声明再次得到解决:

template<typename T>
auto foo(T x) -> return_type<T> {
    return x;
}

您的示例中没有一个使用
T
作为返回类型。实际上,您期望得到什么?模板不是你完全打破语法规则的魔杖。通过模板专门化,你可以为函数模板提供一个替代(专门化)实现;您无法更改其原型。作为其他解决方法,您具有skypjack示例中的返回类型特征,或者在您的示例中,只是一个重载:
double foo(double x)我认为您在概念上寻找的是重载,而不是专门化。编译器应使用“您不应传递”错误(半cit)拒绝该代码。:-)@当具有完全相同参数列表的函数模板具有不同的
std::enable_if_t
返回类型时,skypjack,这样对于每个
t
foo
最多可以引用一个重载,这实际上是一个有用的功能。@hvd嗯,对,我确实经常使用它。我只是开玩笑。:-)
struct last_key{};
struct last_value{};

template<typename key, typename k = last_key, typename v = last_value, typename ...pairs>
struct type_map {
    static_assert(sizeof...(pairs) % 2 == 0, "Last key does not have a value");
    using type = typename std::conditional<std::is_same<key, k>::value,
        v,
        typename type_map<key, pairs...>::type>::type;
};

template<typename key>
struct type_map<key> {
    using type = int;
};
template<typename key>
using return_type = typename type_map<key, double, double>::type;
template<typename T>
auto foo(T x) -> return_type<T> {
    return x;
}
// Specialization.
template<>
auto foo(double x) -> double {
    return x;
}
auto a = foo(1);
auto b = foo(1.0);
std::cout << std::is_same<decltype(a), int>::value << std::endl;
std::cout << std::is_same<decltype(b), double>::value << std::endl;
1
1