C ++에서 두 번째 템플릿 인수를 추측하지 못하게하려면 어떻게해야합니까?


26

그 안에 어딘가에 다음 코드가 있는 C ++ 라이브러리 ( strf )를 사용하고 있습니다.

namespace strf {
template <typename ForwardIt>
inline auto range(ForwardIt begin, ForwardIt end) { /* ... */ }

template <typename Range, typename CharT>
inline auto range(const Range& range, const CharT* sep) { /* ... */ }
}

이제 strf::range<const char*>(some_char_ptr, some_char_ptr + some_length)코드에서 사용 하고 싶습니다. 그러나 그렇게하면 CUDA 10.1의 NVCC에서 다음과 같은 오류가 발생합니다.

error: more than one instance of overloaded function "strf::range" matches the argument list:
            function template "auto strf::range(ForwardIt, ForwardIt)"
            function template "auto strf::range(const Range &, const CharT *)"
            argument types are: (util::constexpr_string::const_iterator, util::constexpr_string::const_iterator)

라이브러리 코드는 아마도이 (예를 들어, 사용을 방지하기 위해 변경 될 수 있습니다 :

inline auto range(const typename std::enable_if<not std::is_pointer<typename std::remove_cv<Range>::type>::value, Range &>::type range, const CharT* sep)

Range포인터가 아닌지 확인하기 위해 ); 하지만 지금은 변경할 수 없습니다. 대신, 어떻게 든 하나의 템플릿 인수 만 지정하고 다른 하나는 추론하지 않는다는 것을 실제로 컴파일러에게 알리고 싶습니다.

내가 할 수 있습니까?

C ++ 11 및 C ++ 14에 대한 답변을 부탁드립니다. 추론 가이드와 관련된 C ++ 17 답변은 관련성이 적지 만 게시 한 경우 게시하십시오 (향후 NVCC 버전의 경우 ...)


업데이트 : strf 라이브러리 자체는이 상황을 피하기 위해 업데이트되었지만 질문은 요청대로 나타납니다.


1
얇게 감싸는 사용자 정의 반복자를 전달하는 것 char*같지만 해결책은 아닙니다.
Konrad Rudolph

1
@ KonradRudolph : 해결 방법이지만 내 질문에 대답하지 않습니다. 실제로 이미 다른 해결 방법 (/*...*/에있는 내용)이 있지만 여기에서 높은 길을 가고 싶습니다.
einpoklum

1
이 경우 불행히도 내 (추측 된) 답변은 "수행 할 수 없습니다". 공정하게하기 위해 제안 된 해결 방법을 내 코드로 수락 할 것인지 확실하지 않습니다.
Konrad Rudolph

간단히 말하면 : 일반적인 솔루션을 원하십니까? 이것은 항상 하나의 매개 변수와 두 개의 매개 변수로 템플릿 오버로드를 구분하는 데 도움이됩니까?이 경우에만 적합한 솔루션을 원하십니까?
호두

@ 호두 : 일반적인 해결책이 더 좋을 것입니다. 내 특정 시나리오는 주로 문제의 동기입니다.
einpoklum

답변:


16
template<typename T>
inline constexpr auto range1_ptr = strf::range<T>;

template<typename T>
inline decltype(auto) range1(T begin, T end) {
    return range1_ptr<T>(begin, end);
}

그런 다음 range1대신에 전화하십시오 strf::range.

range1_ptr<T>(...)하나의 템플릿 인수를 사용하여 템플릿을 명시 적으로 호출하는 데 항상 사용할 수 있지만 인수에서 추론하지는 않습니다. range1원본 strf::range템플릿 에서 공제를 복제합니다 .

이 작품 때문에 [temp.deduct.funcaddr] / (1)는 가상 호출의 매개 변수 및 인수 목록 것처럼 각 후보의 함수 템플릿에서 수행되는 변환의 대상 유형이없는 함수의 주소를 복용 때 템플릿 인수 공제가 말한다 빈. 따라서 두 개의 템플리트 매개 변수를 사용하여 두 번째 과부하에 대해 두 번째 템플리트 인수를 추론 할 수 없습니다. 남은 유일한 후보는 첫 번째 과부하이며 함수 포인터의 대상으로 선택됩니다.

하나의 인수 만있는 유효한 template-id를 구성 할 수있는 두 번째 후보 함수 템플리트가없는 한 range1_ptr항상 하나의 인수를 사용하여 함수 템플리트를 명확하게 호출하는 데 사용할 수 있습니다. 그렇지 않으면, 인스턴스화 range1_ptr하면 모호함으로 인해 오류가 발생합니다.


모호하지 strf::range<T>않습니까?
einpoklum

1
@einpoklum GCC와 Clang에서 잘 컴파일됩니다. 나는 표준을 확인하지는 않았지만 그것이 모호하다고 가정하면 놀랄 것입니다.
호두

함수 이름을 pretty_please_with_sugar_on_top()?로 변경해야 할 수도 있습니다 . ... C ++ 이상한 때로는 될 수 있습니다 ...
einpoklum

허용 된 답변을
제거했습니다. :-P

11

통과하는 것은 using어떻습니까?

using tfp = void(*)(char const *, char const *);

tfp x = &strf::range;

char const * a = "abcd";

(*x)(a, a+2);

그리고 이것은 컴파일됩니까? 두 번째 줄은 특히 의심스러워 보입니다.
einpoklum

@einpoklum-재미 있지 않습니까?
max66

@einpoklum-불행히도 일반적인 해결책은 아닙니다. 이 경우 작동합니다 (잘못되지 않은 경우) 첫 번째 range()버전 만 호환됩니다 tpf. 다른 경우는 다를 수 있습니다.
max66

@einpoklum-두 번째 줄에서 템플릿 매개 변수를 설명 할 수도 있습니다 ( tfp x = &strf::range<char const *>;); 이 방법은 당신이 호두의 것과 거의 동등한 일반적인 솔루션을 가정
max66

0

해결책은

1) 먼저 두 번째 인수의 유형을 지정해야합니다. (char *)(some_char_ptr + some_length)

2) const둘 다 사용하지 마십시오 .

strf::range((char *)some_char_ptr, (char *)(some_char_ptr + some_length));

당신은 대체를 시도 할 수 있습니다 (char *)(const char *)왼쪽 또는 오른쪽에, 그것은 여전히 작동합니다.


인수가 const데이터를 가리키는 경우 이것은 매우 추악합니다 .
aschepler

1. 두 번째 주장 은 없습니다 . 단일 인수 템플릿을 원합니다. 2. 재미있는 핵! 첫 번째 제안에 -1, 두 번째 제안에 +1
:-P
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.