람다에서 비 스칼라 유형으로의 변환이 요청되었습니다.

Dec 08 2020

사용할 때마다 고정되거나 재 계산되는 모든 유형의 값을 가질 수 있도록이 클래스를 만들었습니다.

template<typename T>
class Value {
    private:
    bool fixed;
    union {
        T value;
        std::function<T()> get;
    };
    public:
    Value(const T& value) : fixed(true), value(value) {}
    Value(const std::function<T()>& get) : fixed(false), get(get) {}
    Value(const T *pointer) : Value([pointer]() { return *pointer; }) {}
    ~Value() {}
    operator T() { return fixed ? value : get(); }
};

다음 식은 모두 제대로 작동하는 것 같습니다.

Value<double> a = 2.2;
double b = 1.;
double c = a;
Value<double> d = &b;
Value<int> e = Value<int>([]() { return 1.; });

하지만 내가하려고 할 때 :

Value<double> f = []() { return 1.; };

컴파일 오류가 발생합니다.

error: conversion from 'main()::<lambda()>' to non-scalar type 'Value<double>' requested

여기 에서이 예제를 시도해 볼 수 있습니다 .

할당은 왜 작동하고 작동 T하지 std::function<T()>않으며 어떻게 그렇게 할 수 있습니까?

참고 : 이 답변을 알고 있지만 .NET과 같이 생성자를 명시 적으로 호출하지 않고 문제를 해결하는 방법을 명확하게 알지 못했습니다 Value<double> e.

답변

4 Slava Dec 08 2020 at 00:22

할당은 std :: function <T ()>이 아닌 T에 대해 작동하는 이유는 무엇이며 어떻게 그렇게 할 수 있습니까?

코드는 할당을 사용하지 않지만 복사 초기화 및

또한 복사 초기화의 암시 적 변환은 초기화 프로그램에서 직접 T를 생성해야하는 반면, 직접 초기화는 초기화 프로그램에서 T 생성자의 인수로의 암시 적 변환을 예상합니다.

따라서 작동하게하려면 ctor가 람다를 직접 받아들이도록 만들어야합니다 (간단한 예제입니다).

template<typename T>
class Value {
    std::function<T()> get;    
public:
    
    template<class Y>
    Value(Y lambda ) : get( std::move( lambda ) )  {}
};

라이브 코드std::enable_if C ++ 20이이 ctor에 허용되는 경우 또는 개념을 사용하여 제한을 추가하고 싶을 것 입니다.이 형식에서이 생성자는 다른 오버로드가 허용하지 않을 경우 허용하려고 시도 할 것이며 암호 오류를 생성 할 수 있습니다. 그리고이 enable_if 템플릿 매개 변수가 람다 (특정 서명 포함) 에 따르면 다음 과 같이 간단 할 수 있습니다.

template<class Y, typename = decltype(std::declval<Y&>()())>
Value(Y lambda ) : get( std::move( lambda ) )  {}

C ++ 14를 지원합니다. 다음은 이 생성자가 유형의 이니셜 라이저에 사용되지 않음을 알 수있는 또 다른 라이브 예제 입니다 int.

 Value<double> d2 = 123;

prog.cpp : 9 : 5 : 참고 : 후보 템플릿 무시 : 대체 실패 [with Y = int] : 호출 된 개체 유형 'int'는 함수 또는 함수 포인터가 아닙니다. Value (Y lambda) : get (std :: move (lambda )) {}

4 NathanOliver Dec 08 2020 at 00:17

람다는 std::function. 그것은 당신이 할 때 의미

Value<double> f = []() { return 1.; };

당신은 변환해야 []() { return 1.; }std::function사용자 정의 변환되는, 다음은 변환해야 std::functionValue<double>다른 사용자 정의 변환이다. 그것은 당신이 그러한 변환을 한 번만 허용했을 때 두 개의 사용자 정의 변환입니다. 이것이 코드가 컴파일되지 않는 이유입니다.