【问题标题】:C++ function pointers name lookup inside function template函数模板内的 C++ 函数指针名称查找
【发布时间】:2017-12-13 23:39:52
【问题描述】:

我正在尝试理解名称查找和参数依赖查找。我创建了一个小示例。

已编辑:

https://godbolt.org/g/rMWUbe

#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?正如我预期的那样在main函数里面然后看到函数void g(const MyClass*)

我想要获得的是能够为不同的不同类型调用不同的函数,但不需要转发声明它们。

我在 Ubuntu 16.04 上使用 g++ 5.4.0

【问题讨论】:

  • 您的意思是说&amp;g 编译不正确?没有g
  • 即使没有 c++ 标准集,您的代码也可以使用 vs 2017 (15.5.1)、VC 19.12.something 为我编译。
  • g_call 取决于 T - 但我不确定这有什么关系;您的问题不在于查找g_call,而是查找g。当它出现在函数调用中时,它会被查找两次——在定义点进行普通查找,在实例化点进行 ADL(找到它的是后者)。当它出现在&amp;g 中时,它不是一个从属名称,并且只在定义点查找一次。
  • @SornelHaetir 它之所以有效,是因为众所周知,MSVC 不实现两阶段查找,并将所有查找延迟到实例化点。只要f 未被实际使用,它就会愉快地编译template &lt;typename T&gt; void f() { random garbage here; } (Demo)
  • 您要求解决方法,但您没有描述您想要的。您只是显示无法编译的代码。我可以让你编译无数种方法,但没有线索知道你试图解决的潜在问题是什么,我不知道哪个子集对你有用(如果有的话),而且 SO 有一个帖子长度限制是有限的。

标签: c++ c++11 argument-dependent-lookup name-lookup


【解决方案1】:
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;
};

需要,因为您不能在 中使用lambdas 在constexpr 表达式中。

在以前的 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;
};

【讨论】:

  • @horatiu 虽然我没有解释为什么你的代码不起作用,但我不清楚我的技术不能解决你更新的问题。使用无状态 lambda 强制 ADL...
  • decltype(t) 所以...T? :)
  • @barry 它是从 OP 的原始问题中复制/粘贴的。 ;) 清理干净。
  • @Yakk 通过您的更改,我设法编译了它,但我必须使用 c++17 并进行一些小的更改。如果我错了,请纠正我,但你不能在 c++14 中使用 constexpr lambda 函数。
  • @HoratiuVultur 啊,我错过了 constexpr。好吧,您可以手动编写一个等效于 lambda 的 constexpr,它只是更冗长。
【解决方案2】:

根据 Yakk 的回答和n4487,我设法实现了一个我设法用 c++14 编译的解决方案。

https://godbolt.org/g/BRee4u

#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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多