C++ SFINAE 在引用类型和转换为引用的参数之间选择重载?
C++ SFINAE to choose an overload between reference type and argument converted to reference?
考虑:
struct BigData {...};
// Let's get a BigData by reference, but use it as a value.
// For example, we may want to make a copy of the object, but we'd
// like to avoid the pass-by-value overhead at the call site.
template <typename T, *some template magic?*>
void processData(T& t) {
printf("Your BigData was converted to a reference argument.\n");
...
}
// Now, we want an overload that will know that there wasn't a
// conversion to reference and will treat it like a reference.
// Perhaps we are adding this BigData to a list of references.
template <typename T, *some template magic?*>
void processData(T& t) {
printf("You gave me a BigData reference.\n");
...
}
int main() {
BigData data;
BigData& ref = data;
processData(data); // "Your BigData was converted to a reference argument."
processData(ref); // "You gave me a BigData reference."
return 0;
}
简而言之,我的 objective 是要有重载来区分引用绑定的来源 - 类型的值或(已经)引用类型。我尝试将 std::enable_if
和系列与引用和不引用 T
的重载结合使用,但我找不到实现此目的的方法。非常感谢任何帮助!
我认为您不了解引用绑定的工作原理。您不仅可以将一个引用绑定到另一个引用,还可以绑定一个值类型的值(即没有引用限定)
所以如果你想通过引用传递BigData
对象,你只需要执行以下操作
template <typename T>
void processData(T& t) {
cout << "Your BigData was passed as a reference argument" << endl;
// ...
}
int main() {
BigData data;
BigData& ref = data;
processData(data);
processData(ref);
return 0;
}
这里两个 processData
调用都将通过引用传递 BigData
对象(即在函数调用期间没有副本)。
您不需要处理传递给函数的对象是与正常情况不同的引用的情况。 std::enable_if
这里不需要。
此外,无法区分这两种情况,无论是使用 data
还是 ref
作为函数的参数,因为它们都是左值。如果要检查表达式的 decltype
是否为引用,则必须执行以下操作
#include <iostream>
#include <type_traits>
using std::cout;
using std::endl;
template <typename T, std::enable_if_t<std::is_reference<T>::value>* = nullptr>
void processData(std::add_lvalue_reference_t<T>) {
cout << "You gave me a reference argument." << endl;
}
template <typename T, std::enable_if_t<!std::is_reference<T>::value>* = nullptr>
void processData(std::add_lvalue_reference_t<T>) {
cout << "Your argument was converted to a reference." << endl;
}
int main() {
auto integer_value = 1;
const auto& integer_ref = 2;
processData<decltype(integer_value)>(integer_value);
processData<decltype(integer_ref)>(integer_ref);
return 0;
}
考虑:
struct BigData {...};
// Let's get a BigData by reference, but use it as a value.
// For example, we may want to make a copy of the object, but we'd
// like to avoid the pass-by-value overhead at the call site.
template <typename T, *some template magic?*>
void processData(T& t) {
printf("Your BigData was converted to a reference argument.\n");
...
}
// Now, we want an overload that will know that there wasn't a
// conversion to reference and will treat it like a reference.
// Perhaps we are adding this BigData to a list of references.
template <typename T, *some template magic?*>
void processData(T& t) {
printf("You gave me a BigData reference.\n");
...
}
int main() {
BigData data;
BigData& ref = data;
processData(data); // "Your BigData was converted to a reference argument."
processData(ref); // "You gave me a BigData reference."
return 0;
}
简而言之,我的 objective 是要有重载来区分引用绑定的来源 - 类型的值或(已经)引用类型。我尝试将 std::enable_if
和系列与引用和不引用 T
的重载结合使用,但我找不到实现此目的的方法。非常感谢任何帮助!
我认为您不了解引用绑定的工作原理。您不仅可以将一个引用绑定到另一个引用,还可以绑定一个值类型的值(即没有引用限定)
所以如果你想通过引用传递BigData
对象,你只需要执行以下操作
template <typename T>
void processData(T& t) {
cout << "Your BigData was passed as a reference argument" << endl;
// ...
}
int main() {
BigData data;
BigData& ref = data;
processData(data);
processData(ref);
return 0;
}
这里两个 processData
调用都将通过引用传递 BigData
对象(即在函数调用期间没有副本)。
您不需要处理传递给函数的对象是与正常情况不同的引用的情况。 std::enable_if
这里不需要。
此外,无法区分这两种情况,无论是使用 data
还是 ref
作为函数的参数,因为它们都是左值。如果要检查表达式的 decltype
是否为引用,则必须执行以下操作
#include <iostream>
#include <type_traits>
using std::cout;
using std::endl;
template <typename T, std::enable_if_t<std::is_reference<T>::value>* = nullptr>
void processData(std::add_lvalue_reference_t<T>) {
cout << "You gave me a reference argument." << endl;
}
template <typename T, std::enable_if_t<!std::is_reference<T>::value>* = nullptr>
void processData(std::add_lvalue_reference_t<T>) {
cout << "Your argument was converted to a reference." << endl;
}
int main() {
auto integer_value = 1;
const auto& integer_ref = 2;
processData<decltype(integer_value)>(integer_value);
processData<decltype(integer_ref)>(integer_ref);
return 0;
}