C++ 函数指针名称在函数模板中查找
C++ function pointers name lookup inside function template
我试图理解名称查找和参数依赖性 lookup.I 创建了一个小示例。
已编辑:
#include <iostream>
void g(const int*) {}
template <typename T>
struct TypeResolution;
template <typename T>
struct TypeResolution<T&> {
typedef const T* type;
static constexpr void (*func_ptr)(TypeResolution::type) = g;
static constexpr void *func_ptr_void = (void*)func_ptr;
};
template <typename T>
struct TypeResolution {
typedef const T* type;
static constexpr void (*func_ptr)(TypeResolution::type) = g;
static constexpr void *func_ptr_void = (void*)func_ptr;
};
void foo_impl(void *[], void *[]) {
//Some work here, that will be in a different file or library
}
template <typename... ARGS>
void foo(ARGS && ... args) {
void *func_ptrs[] = { TypeResolution<ARGS>::func_ptr_void... };
void *args_ptrs[] = {(void*)&args...};
foo_impl(func_ptrs, args_ptrs);
}
struct MyClass {};
void g(const MyClass*) {}
int main(int argc, char* argv[]) {
int i = 1;
foo(i);
int j = 2;
foo(i, j);
MyClass c;
foo(c); //This fails.
}
所以我的问题是,为什么它不能编译?或者更简单地说,为什么在 TypeResolution 中查找 g 是在声明 class 时发生的,而不是在实例化时发生的?正如我在 main 函数中预期的那样,然后查看函数 void g(const MyClass*)
我想要获得的是能够为不同的不同类型调用不同的函数,而不需要转发声明它们。
我在 Ubuntu 16.04
上使用 g++ 5.4.0
template <typename T>
void foo(T t) {
void(*f)(T) = +[](T x){ return g(std::forward<T>(x)); };
f(t); //This compiles
g(t); //This compiles
}
这可能就是您想要的。请注意,参数在 f 内移动了一次,这对于基本类型来说应该无关紧要。
template <class T>
struct TypeResolution;
template <class T>
struct TypeResolution<T&>:TypeResolution<T> {};
template <class T>
struct TypeResolution {
typedef const T* type;
static constexpr void (*func_ptr)(type) = +[](type x){ return g(x); };
static constexpr void *func_ptr_void = (void*)func_ptr;
};
在 constexpr
表达式中需要 c++17 because you cannot use lambdas in c++14 or c++11。
在以前的 C++ 版本中,我们可以这样做:
template <class T>
struct TypeResolution {
typedef const T* type;
static void invoke_g(type t) { g( t ); }
static constexpr void (*func_ptr)(type) = invoke_g;
static constexpr void *func_ptr_void = (void*)func_ptr;
};
基于 Yakk 的回答和 n4487 我设法实现了一个我设法用 c++14 编译的解决方案。
#include <iostream>
#include <type_traits>
#include <string>
void g(int*) {}
template <typename T>
struct TypeResolution;
template <typename T>
struct TypeResolution<T&> {
struct Inner {
static constexpr void foo(T* t) { g(t); }
};
static constexpr void *func_ptr_void = (void*)Inner::foo;
};
template <typename T>
struct TypeResolution {
struct Inner {
static constexpr void foo(T* t) { g(t); }
};
static constexpr void *func_ptr_void = (void*)Inner::foo;
};
void foo_impl(void *func_args[], void *data_args[]) {
//Some work here, that will be in a different file or library
}
template <typename... ARGS>
void foo(ARGS && ... args) {
void *func_ptrs[] = { TypeResolution<ARGS>::func_ptr_void... };
void *args_ptrs[] = {(void*)&args...};
foo_impl(func_ptrs, args_ptrs);
}
struct MyClass {};
void g(const MyClass*) {}
int main(int argc, char* argv[]) {
int i = 1;
foo(i);
MyClass c;
foo(c);
}
我试图理解名称查找和参数依赖性 lookup.I 创建了一个小示例。
已编辑:
#include <iostream>
void g(const int*) {}
template <typename T>
struct TypeResolution;
template <typename T>
struct TypeResolution<T&> {
typedef const T* type;
static constexpr void (*func_ptr)(TypeResolution::type) = g;
static constexpr void *func_ptr_void = (void*)func_ptr;
};
template <typename T>
struct TypeResolution {
typedef const T* type;
static constexpr void (*func_ptr)(TypeResolution::type) = g;
static constexpr void *func_ptr_void = (void*)func_ptr;
};
void foo_impl(void *[], void *[]) {
//Some work here, that will be in a different file or library
}
template <typename... ARGS>
void foo(ARGS && ... args) {
void *func_ptrs[] = { TypeResolution<ARGS>::func_ptr_void... };
void *args_ptrs[] = {(void*)&args...};
foo_impl(func_ptrs, args_ptrs);
}
struct MyClass {};
void g(const MyClass*) {}
int main(int argc, char* argv[]) {
int i = 1;
foo(i);
int j = 2;
foo(i, j);
MyClass c;
foo(c); //This fails.
}
所以我的问题是,为什么它不能编译?或者更简单地说,为什么在 TypeResolution 中查找 g 是在声明 class 时发生的,而不是在实例化时发生的?正如我在 main 函数中预期的那样,然后查看函数 void g(const MyClass*)
我想要获得的是能够为不同的不同类型调用不同的函数,而不需要转发声明它们。
我在 Ubuntu 16.04
上使用 g++ 5.4.0template <typename T>
void foo(T t) {
void(*f)(T) = +[](T x){ return g(std::forward<T>(x)); };
f(t); //This compiles
g(t); //This compiles
}
这可能就是您想要的。请注意,参数在 f 内移动了一次,这对于基本类型来说应该无关紧要。
template <class T>
struct TypeResolution;
template <class T>
struct TypeResolution<T&>:TypeResolution<T> {};
template <class T>
struct TypeResolution {
typedef const T* type;
static constexpr void (*func_ptr)(type) = +[](type x){ return g(x); };
static constexpr void *func_ptr_void = (void*)func_ptr;
};
在 constexpr
表达式中需要 c++17 because you cannot use lambdas in c++14 or c++11。
在以前的 C++ 版本中,我们可以这样做:
template <class T>
struct TypeResolution {
typedef const T* type;
static void invoke_g(type t) { g( t ); }
static constexpr void (*func_ptr)(type) = invoke_g;
static constexpr void *func_ptr_void = (void*)func_ptr;
};
基于 Yakk 的回答和 n4487 我设法实现了一个我设法用 c++14 编译的解决方案。
#include <iostream>
#include <type_traits>
#include <string>
void g(int*) {}
template <typename T>
struct TypeResolution;
template <typename T>
struct TypeResolution<T&> {
struct Inner {
static constexpr void foo(T* t) { g(t); }
};
static constexpr void *func_ptr_void = (void*)Inner::foo;
};
template <typename T>
struct TypeResolution {
struct Inner {
static constexpr void foo(T* t) { g(t); }
};
static constexpr void *func_ptr_void = (void*)Inner::foo;
};
void foo_impl(void *func_args[], void *data_args[]) {
//Some work here, that will be in a different file or library
}
template <typename... ARGS>
void foo(ARGS && ... args) {
void *func_ptrs[] = { TypeResolution<ARGS>::func_ptr_void... };
void *args_ptrs[] = {(void*)&args...};
foo_impl(func_ptrs, args_ptrs);
}
struct MyClass {};
void g(const MyClass*) {}
int main(int argc, char* argv[]) {
int i = 1;
foo(i);
MyClass c;
foo(c);
}