함수 포인터 배열에서 함수 인수를 템플릿 인수로 전달


9

함수 포인터 배열에서 함수 인수를 템플릿 인수로 전달하고 싶습니다. Intellisense에서 무언가 잘못되었다고 불평하지만 내 코드는 MSVC를 사용하여 컴파일하는 것 같습니다. gcc와 clang은 모두 코드를 컴파일하지 못합니다.

다음 예제를 고려하십시오.

static void test() {}

using FunctionPointer = void(*)();

static constexpr FunctionPointer functions[] = { test };

template <FunctionPointer function>
static void wrapper_function()
{
    function();
}

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<functions[0]>();  // Error?
}

MSVC 는 코드를 컴파일하지만 Intellisense는 다음 오류를 발생시킵니다.invalid nontype template argument of type "const FunctionPointer"

gcc 가 다음 메시지와 함께 컴파일에 실패합니다 :

<source>: In function 'int main()':
<source>:19:33: error: no matching function for call to 'wrapper_function<functions[0]>()'
   19 |  wrapper_function<functions[0]>();  // Error?
      |                                 ^
<source>:8:13: note: candidate: 'template<void (* function)()> void wrapper_function()'
    8 | static void wrapper_function()
      |             ^~~~~~~~~~~~~~~~
<source>:8:13: note:   template argument deduction/substitution failed:
<source>:19:30: error: '(FunctionPointer)functions[0]' is not a valid template argument for type 'void (*)()'
   19 |  wrapper_function<functions[0]>();  // Error?
      |                   ~~~~~~~~~~~^
<source>:19:30: note: it must be the address of a function with external linkage

clang 이 다음 메시지와 함께 컴파일에 실패합니다 :

<source>:19:2: error: no matching function for call to 'wrapper_function'
        wrapper_function<functions[0]>();  // Error?
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:13: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'function'
static void wrapper_function()
            ^
1 error generated.

질문 :

wrapper_function<functions[0]>();유효하거나하지?

그렇지 않은 경우 functions[0]템플릿 인수로 전달할 수있는 작업 이 wrapper_function있습니까? 내 목표는 컴파일 타임에 content와 함께 새로운 함수 포인터 배열을 만드는 것입니다 { wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }.


흠, 흥미 롭습니다. 문제는 유형 대신 값 (포인터)을 사용하고 있다고 생각했습니다. 그러나 wrapper_function<decltype(functions[0])>()컴파일 조차 하지 않습니다.
CoryKramer

6
C ++ 17에서 작동하는 것 같습니다 ... 이제 표준의 차이점을 찾기 위해 ...
AndyG

답변:


5

wrapper_function<functions[0]>();다음과 같은 이유로 표현 이 금지됩니다.

14.3.2 템플릿 비 유형 인수 [temp.arg.nontype]

템플릿이 아닌 템플릿이 아닌 템플릿 매개 변수의 템플릿 인수는 다음 중 하나 여야합니다.

[...]

— 정적 저장 공간> 지속 시간 및 외부 또는 내부 연결을 가진 객체의 주소 또는 함수 템플릿 및 함수 template-id를 포함하지만 비 정적 클래스 멤버는 제외하고 외부 또는 내부 연결을 가진 함수의 주소를 지정하는 상수 표현식 (5.19) 이름이 함수 또는 배열을 참조하는 경우 &를 생략 할 수 있고 해당 템플리트 매개 변수가 참조 인 경우 생략해야한다는 점을 제외하고 &는 괄호를 & id- 표현식으로 무시합니다. [...]

포인터를 형식 이외의 템플릿이 아닌 템플릿 인수로 사용하는 것은 금지되어 &id있으므로 기본적으로 다음과 같이 작동합니다.

static void test() {}

using FunctionPointer = void(*)();

static constexpr FunctionPointer functions[] = { test };

template <FunctionPointer function>
static void wrapper_function()
{
    function();
}

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<&test>();  // OK
}

C ++ 14 옵션으로 컴파일하면 다음 스 니펫이 작동하지 않습니다.

constexpr auto func = &test;
wrapper_function<func>();

C ++ 17 옵션으로 컴파일하면 접근 방식과 위의 방법이 모두 작동합니다.

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<&test>();  // OK
    wrapper_function<func>();  // OK

    wrapper_function<functions[0]>();  // OK
}

라이브 보기


예제에서 보여 주듯이 상수 형식 &id뿐만 아니라 idnull 포인터 값도 명시 적으로 허용 되므로 form 뿐만 아니라 함수 에도 허용됩니다.
호두

C ++ 17은이를 " 변환 된 상수 표현식 "으로 대체합니다 . 즉, 상수 표현식을 체인화 할 수 있으므로 wrapper_function<func>()작동합니다.
rustyx

Ok는 답을 전체적으로 작성한 후에 답변을 확인하고 업데이트합니다. Tnx
NutCracker
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.