#include <iostream>
#include <cmath>
#include <type_traits>
template <typename T>
void f(T, T) // 1
{
std::cout << "Primary\n";
}
template <typename T>
void f(T, std::enable_if_t<std::is_floating_point_v<T>, T>) // 2
{
std::cout << "Special\n";
}
/*template <typename T>
std::enable_if_t<std::is_floating_point_v<T>> f(T, T) // 3
{
std::cout << "Special\n";
}*/
int main()
{
f(1.1, 1.1); // prints 'Primary'
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,std::enable_if应用于第二个函数模板重载的函数类型。该函数是通过 [T = double] 推导来调用的,并且它调用重载 1。但是,如果我注释掉重载 2 并将其替换为重载 3,那么编译器会抱怨该调用不明确。我也期望在第一种情况下,为什么编译器更喜欢重载 1 而不是 2?
我阅读了“函数模板重载”部分,但对我来说,重载 2 看起来更专业。
c++ language-lawyer enable-if function-templates-overloading
在C++ Primer一书中,有一个关于函数模板重载的例子:
Run Code Online (Sandbox Code Playgroud)// print any type we don't otherwise handle template <typename T> string debug_rep(const T &t) { cout << "debug_rep(T const&)\n"; ostringstream ret; // see § 8.3 (p. 321) ret << t; // uses T's output operator to print a representation of t return ret.str(); // return a copy of the string to which ret is bound } // print pointers as their pointer value, followed by the object to which the pointer points // NB: this …
c++ template-argument-deduction function-templates-overloading
在下面的两个模板函数中,我们尝试了更多的约束:
template<typename T>
concept SmallVar = (sizeof(T) <= sizeof(int));
void print(SmallVar auto t) { // 1
std::cout << t << std::endl;
}
void print(const auto& t) { // 2
std::cout << t << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
当使用 int 调用时,Clang 和 GCC 有所不同:
int main() {
print(6); // clang accepts and prefers 1, gcc sees here ambiguity
}
Run Code Online (Sandbox Code Playgroud)
哪一个是正确的?
代码: https: //godbolt.org/z/x71zjzoTa
这里我们有is_base_of来自cppreference.com的模板实现:
namespace details {
template <typename B>
std::true_type test_pre_ptr_convertible(const B*); //1
template <typename>
std::false_type test_pre_ptr_convertible(const void*); //2
template <typename, typename>
auto test_pre_is_base_of(...)->std::true_type; //3
template <typename B, typename D>
auto test_pre_is_base_of(int) ->
decltype(test_pre_ptr_convertible<B>(static_cast<D*>(nullptr)));
}
template <typename Base, typename Derived>
struct is_base_of :
std::integral_constant<
bool,
std::is_class<Base>::value&& std::is_class<Derived>::value&&
decltype(details::test_pre_is_base_of<Base, Derived>(0))::value
> { };
Run Code Online (Sandbox Code Playgroud)
还有一些私有继承:
class A {};
class B : A {};
Run Code Online (Sandbox Code Playgroud)
is_base_of<A,B>::value给出 true 和声明号。3 是最佳匹配。声明编号 1 作为候选者失败(传递了一个指向私有子类对象的指针)并且声明号。2 被忽略。但为什么?不是void*每个指针类型都能很好匹配吗?如果声明没有。3 未提供代码将无法编译。我的问题是为什么声明没有。3 需要提供此代码才能成功编译吗?为什么声明没有。1 和没有。2个还不够?
c++ overloading template-meta-programming function-templates-overloading
下面是一个非常简短的例子。
#include <utility>
template<typename T, typename = void>
struct A {};
template<typename T, typename U>
void f(A<std::pair<T,U>>) {}
template<typename U>
void f(A<std::pair<int,U>, std::enable_if_t<std::is_same_v<int,U>>>) {}
int main() {
A<std::pair<int, int>> x;
f(x);
}
Run Code Online (Sandbox Code Playgroud)
错误很明显
uffa.cpp: In function ‘int main()’:
uffa.cpp:22:4: error: call of overloaded ‘f(A<std::pair<int, int> >&)’ is ambiguous
22 | f(x);
| ~^~~
uffa.cpp:10:6: note: candidate: ‘void f(A<std::pair<_T1, _T2> >) [with T = int; U = int]’
10 | void f(A<std::pair<T,U>>) {}
| ^
uffa.cpp:18:6: note: candidate: ‘void f(A<std::pair<int, U>, …Run Code Online (Sandbox Code Playgroud) c++ sfinae language-lawyer enable-if function-templates-overloading
Since std::format isn't supported everywhere, and I didn't want another large dependency like fmt, I wanted to quickly roll my own to_string solution for a number of types. The following is the code.
#include <ranges>
#include <string>
#include <concepts>
template<typename Type>
constexpr std::string stringify(const Type &data) noexcept;
template<typename Type> requires std::integral<Type>
constexpr std::string stringify(const Type &data) noexcept {
return std::to_string(data);
}
template<typename Type>
constexpr std::string stringify_inner(const Type &data) noexcept {
return stringify(data);
}
template<typename Type> requires std::ranges::range<Type>
constexpr std::string …Run Code Online (Sandbox Code Playgroud) c++ algorithm templates c++20 function-templates-overloading
下面有一些非常基本的 C++ 函数模板重载解析示例(从实际代码中最小化)
struct S {
S() {}
S(int) {}
};
template <typename T = S>
void foo(T x) { std::cout << "S" << std::endl; }
template <>
void foo<S>(S x) { std::cout << "S spc" << std::endl; }
int main() {
foo({});
foo(0);
}
Run Code Online (Sandbox Code Playgroud)
这里我们有两种情况。在第一种情况下编译器应默认初始化某些东西(如 S)在第二种情况下将 int 转换为某些东西(如 S)
我相信在这两种情况下,专业化都会赢得重载,因为专业化完全匹配,并且通过偏序 [temp.deduct.partial] 比主模板更专业
但是这个例子中的 clang 11 和 gcc 10.2 都同意在第二种情况下主模板获胜。这是两个编译器中的错误还是(可能)我对 C++ 标准不了解?
我应该如何修改我当前的函数签名
template<class TypeData,typename TypeFunc1 = Identity,typename TypeFunc2>
bool isPrime(const TypeData& n,TypeFunc1 calcSqrt = {},TypeFunc2 isDivisible = [](const TypeData& a,const TypeData& b) {return a%b==0;},const bool debug = false)
Run Code Online (Sandbox Code Playgroud)
为了被调用
auto fSqrt = [](decltype(n) v) {return std::sqrt(static_cast<float>(v));};
std::cout<<(isPrime(n,fSqrt)?"Positive":"Negative")<<'\n';
Run Code Online (Sandbox Code Playgroud)
Visual Studio 2019 提供
C2783 'bool isPrime(const TypeData &,TypeFunc1,TypeFunc2,const bool)':无法推导出 'TypeFunc2' 的模板参数
不过,没有 一切都很好TypeFunc2 isDivisible = [](const TypeData& a,const TypeData& b) {return a%b==0;}。
传递默认 lambda 的正确语法是什么?
请帮助我。
c++ ×8
function-templates-overloading ×8
c++20 ×3
enable-if ×2
templates ×2
algorithm ×1
c++17 ×1
lambda ×1
overloading ×1
sfinae ×1