C ++函数指针在函数模板中查找名称

时间:2017-12-13 23:39:52

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

我试图理解名称查找和参数依赖项查找。我创建了一个小例子。

编辑:

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

2 个答案:

答案 0 :(得分:2)

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表达式中使用lambdas。

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

答案 1 :(得分:0)

根据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);
}