[英]How to compare two typenames for equality in C++?
Suppose I have a template of a function, say 假设我有一个函数的模板,比方说
template<typename T>
func(T a, T b, ...) {
...
for (const auto &single : group) {
...
auto c = GivenFunc1(a, b, single, ...);
... }
...
}
However, for T being a special type, say "SpecialType", I want c
being calculated by "GivenFunc2" rather than "GivenFunc1". 但是,对于T是一种特殊类型,比如“SpecialType”,我希望c
由“GivenFunc2”而不是“GivenFunc1”计算。 However, I would not like to write a specialization for "SpecialType", since there will be a huge code duplication. 但是,我不想为“SpecialType”编写专门化,因为会有大量的代码重复。 So I want the template function being something like 所以我想模板功能就像
template<typename T>
func(T a, T b, ...) {
...
for (const auto &single : group) {
...
auto c = (T == SpecialType) ? GivenFunc2(a, b, single, ...)
: GivenFunc1(a, b, single, ...);
... }
...
}
Of course, this code does not compile since "T == SpecialType" is not valid. 当然,由于“T == SpecialType”无效,因此该代码无法编译。 So how do I write it in an elegant way? 那么如何以优雅的方式编写它呢?
It's as simple as: 它很简单:
auto c = std::is_same_v<T, SpecialType> ? GivenFunc2(a, b, single, ...)
: GivenFunc1(a, b, single, ...);
If you can't use C++17, replace std::is_same_v<...>
with std::is_same<...>::value
. 如果您不能使用C ++ 17,请将std::is_same_v<...>
替换为std::is_same<...>::value
。
But for this approach to work, both function calls have to be valid for every T
you want to use, even if in reality one of them won't be executed. 但是对于这种工作方法,两个函数调用必须对你想要使用的每个T
都有效,即使实际上其中一个不会被执行。
If it's not the case, you can resort to if constexpr
: 如果不是这样,你可以求助于if constexpr
:
your_type_here c;
if constexpr (std::is_same_v<T, SpecialType>)
c = GivenFunc2(a, b, single, ...);
else
c = GivenFunc1(a, b, single, ...);
(This works only in C++17.) (这仅适用于C ++ 17。)
If you can use C++17 , you can achieve the result in a very clean way (with constexpr
and is_same
): 如果你可以使用C ++ 17 ,你可以用一种非常干净的方式实现结果(使用constexpr
和is_same
):
template<typename T>
func(T a, T b, ...) {
// ...
if constexpr (std::is_same_v<T, SpecialType>) {
// call GivenFunc2
} else {
// call GivenFunc1
}
// ...
}
Pre C++17 you can achieve the same result using techniques such as SFINAE
or "TAG Dispatching". 预C ++ 17可以使用诸如实现相同的结果SFINAE
或“TAG调度”。
Additionally, you can just specialize the portion of the code referring to the function call (easy and avoid code duplication). 此外,您可以专门参考函数调用的代码部分(简单并避免代码重复)。
A short example here : 简单例子在这里 :
template <typename T>
struct DispatcherFn {
auto operator()(const T&, int) {
// call GivenFunc1
}
};
template <>
struct DispatcherFn<SpecialType> {
auto operator()(const SpecialType&, int) {
// GivenFunc2
}
};
template <typename T>
void func(const T& t) {
// ... code ...
auto c = DispatcherFn<T>()(t, 49); // specialized call
}
You can always use template specializations instead of doing type comparisons of template parameters. 您始终可以使用模板特化而不是模板参数的类型比较。 Here's a simplified, working example: 这是一个简化的工作示例:
#include <iostream>
#include <string>
template<typename T>
int GivenFunc1(T a, T b) {
std::cout << "GivenFunc1()" << std::endl;
return 0;
}
template<typename T>
int GivenFunc2(T a, T b) {
std::cout << "GivenFunc2()" << std::endl;
return 1;
}
template<typename T>
void func(T a, T b) {
auto c = GivenFunc2(a, b);
std::cout << c << std::endl;
}
template<>
void func(std::string a, std::string b) {
auto c = GivenFunc1(a, b);
std::cout << c << std::endl;
}
int main() {
func(2,3);
std::string a = "Hello";
std::string b = "World";
func(a,b);
}
See it working online here . 看到它在这里工作。
In c++17 the best solution is if constexpr
. 在c ++ 17中 ,最好的解决方案是if constexpr
。
In c++14 this works: 在c ++ 14中,这适用于:
template<class V>
auto dispatch( V const& ) {
return [](auto&&...targets) {
return std::get<V{}>( std::forward_as_tuple( decltype(targets)(targets)... ) );
};
}
then: 然后:
auto c = dispatch( std::is_same<T, SpecialType>{} )
(
[&](auto&& a, auto&& b){ return GivenFunc2(a, b, single...); },
[&](auto&& a, auto&& b){ return GivenFunc1(a, b, single, ...); }
)( a, b );
does what you want. 做你想要的。 (It is also a function which returns a function which returns a function) (它也是一个返回函数返回函数的函数)
Live example . 实例 。
dispatch
picks one of the two lambdas and returns it at compile time. dispatch
选择两个lambdas中的一个并在编译时返回它。 We then call the picked lambda with a
and b
. 然后我们用a
和b
调用拾取的lambda。 So only the valid one is compiled with a type for a
and b
. 所以只有有效的一个用a
和b
的类型编译。
Convert GivenFunc1
to a functor and specialise that. 将GivenFunc1
转换为GivenFunc1
函数并将其专门化。
template <class T>
class GivenFunc
{
X operator()(T a, T b, Y single)
{
...
}
}
template <>
class GivenFunc<SpecialType>
{
X operator()(SpecialType a, SpecialType b, Y single)
{
...
}
}
Then you can say 然后你可以说
auto c = GivenFunc<T>()(a, b, single);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.