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". However, I would not like to write a specialization for "SpecialType", since there will be a huge code duplication. So I want the template function being something like
但是,对于T是一种特殊类型,比如“SpecialType”,我希望c由“GivenFunc2”而不是“GivenFunc1”计算。但是,我不想为“SpecialType”编写专门化,因为会有大量的代码重复。所以我想模板功能就像
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. So how do I write it in an elegant way?
当然,由于“T == SpecialType”无效,因此该代码无法编译。那么如何以优雅的方式编写它呢?
5 个解决方案
#1
30
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
:
如果不是这样的话,你可以求助于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。)
#2
18
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".
使用SFINAE或“TAG Dispatching”等技术,您可以获得相同的结果。
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
}
#3
12
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.
看到它在这里工作。
#4
6
In c++17 the best solution is if constexpr
.
在c ++ 17中,最好的解决方案是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)
做你想要的。 (它也是一个返回函数的函数,返回一个函数)
dispatch
picks one of the two lambdas and returns it at compile time. We then call the picked lambda with a
and b
. So only the valid one is compiled with a type for a
and b
.
dispatch选择两个lambdas中的一个并在编译时返回它。然后我们用a和b调用拾取的lambda。所以只有有效的一个用a和b的类型编译。
#5
1
Convert GivenFunc1
to a functor and specialise that.
将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);
#1
30
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
:
如果不是这样的话,你可以求助于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。)
#2
18
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".
使用SFINAE或“TAG Dispatching”等技术,您可以获得相同的结果。
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
}
#3
12
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.
看到它在这里工作。
#4
6
In c++17 the best solution is if constexpr
.
在c ++ 17中,最好的解决方案是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)
做你想要的。 (它也是一个返回函数的函数,返回一个函数)
dispatch
picks one of the two lambdas and returns it at compile time. We then call the picked lambda with a
and b
. So only the valid one is compiled with a type for a
and b
.
dispatch选择两个lambdas中的一个并在编译时返回它。然后我们用a和b调用拾取的lambda。所以只有有效的一个用a和b的类型编译。
#5
1
Convert GivenFunc1
to a functor and specialise that.
将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);