programing

Concepts Lite를 사용하여 멤버 함수 템플릿이있는 유형에 대한 개념 지정

nasanasas 2020. 12. 2. 21:26
반응형

Concepts Lite를 사용하여 멤버 함수 템플릿이있는 유형에 대한 개념 지정


Concepts Lite를 사용하여 멤버 함수 템플릿이있는 더 높은 종류의 유형을 제한하는 개념을 지정하려고합니다. 그러나 기술 사양 이나 튜토리얼 에서 개념 내부의 템플릿 문을 다루는 절 을 찾을 수 없습니다 .

어떻게하나요?

예 : HKT멤버 함수 템플릿 이있는 더 높은 종류의 유형이 있다고 가정합니다 F.

template<class T>
struct HKT {
  template<class U> // this looks like e.g. rebind in std::allocators
  auto F(U) -> HKT<U>;
};

이제 이러한 더 높은 종류의 유형을 제한하는 개념을 지정하고 싶습니다.

template <template <class> class HKT, class T>
concept HKTWithTemplateMemberFunctionF {
  return requires(HKT<T> h) { // HKT<T> is a type, h is an object
    // HKT<T> needs to have a member function template that 
    // returns HTK<U> where the type U is to be deduced and
    // it can be any type (it is unconstrained)
    template<class U>  // is there a syntax for this?
    h.F(std::declval<U>()) -> HKT<U>; 
  }
}

다음과 같이 할 수 있습니다.

template <template <class> class HKT, class T, class U>
concept HKTWithTemplateMemberFunctionF {
  return requires(HKT<T> h) {
      h.F(std::declval<U>()) -> HKT<U>;
  }
}

그러나 이것은 U제약 사이트에서 알아야한다는 것을 의미합니다 .

나는 U이것이 왜 문제가 될 수 있는지 알 수 있지만 주어진 대체 가 실패 하는지 여부는 정말로 신경 쓰지 않는다 . 예를 들어 함수가 실패하지 않도록 제약 조건을 적용한 다음 실패하면 제약 조건이 충족되었지만 인스턴스화 시간에 실패합니다. 멤버 함수 템플릿에서 대체에 실패했습니다 (멤버 함수 템플릿이 제한된 경우 도움이 될까요?).


의견에서 원하는 요구 사항에 대해 생각해 보겠습니다.

// HKT<T> needs to have a member function template that 
// returns HTK<U> where the type U is to be deduced and
// it can be any type (it is unconstrained)

Concepts에서는 구체적인 유형에 대한 제약 조건을 기반으로해야하지만 우리가 사용하는 구체적인 유형을 선택하는 데 현명 할 수 있습니다. 당신은 무엇에 의해 뜻하는 U것입니다 어떤 유형입니다. 정말 어떤 유형이 든요? 가능한 가장 작은 제약 조건 집합에 대해 생각하고 U이를 충족하는 유형을 작성해 보겠습니다. 이것은의 원형 으로 알려져 U있습니다.

"모든 유형"에 대한 나의 고토 첫 생각은 실제로는 반 정규 유형일 것입니다. 기본적으로 구성 가능하고 복사 가능하며 할당 가능한 유형입니다. 모든 정상적인 혜택 :

namespace archetypes {
    // private, only used for concept definitions, never in real code
    struct Semiregular { };
}

archetypes::Semiregular 구체적인 유형이므로 개념을 구축하는 데 사용할 수 있습니다.

template <template <class> class HKT, class T>
concept bool HKTWithTemplateMemberFunctionF = 
  requires(HKT<T> h, archetypes::Semiregular r) {
    {h.F(r)} -> HKT<archetypes::Semiregular>
  };

archetypes::Semiregular개인 유형입니다. 그것은 알려진되어서는 안된다 HKT, 그렇다면이 h.F(r)잘 형성되고 반환로 변환 형식은 HKT<archetypes::Semiregular>, 그것은 거의 확실 멤버 함수 템플릿입니다.

그렇다면 질문은 이것이 좋은 원형인가? 우리가해야합니까 Usemiregular 수 또는 유형이 너무 일 불규칙한 것? 필요한 작업이 적을 수록 아키 타입에 더 적은 수의 작업이 있어야합니다. 아마도 필요한 U것은 이동식뿐입니다.

namespace archetypes {
    // private, only used for concept definitions, never in real code
    struct Semiregular { };

    struct Moveable {
        Moveable() = delete;
        Moveable(Moveable&& ) noexcept(false);
        Moveable(Moveable const& ) = delete;
        ~Moveable() = default;

        Moveable& operator=(Moveable const& ) = delete;
        Moveable& operator=(Moveable&& ) noexcept(false);
    };
}

template <template <class> class HKT, class T>
concept bool HKTWithTemplateMemberFunctionF =
  requires(HKT<T> h, archetypes::Moveable m) {
    { h.F(m) } -> HKT<archetypes::Moveable>
  };

우리는 동일한 아이디어를 테스트하고 F()있습니다. 잘 알려지지 않은 유형으로 호출 하고이를 반영하기 위해 반환 유형을 제외하여 함수 템플릿이어야합니다. 그러나 이제 우리는 유형에 더 적은 기능을 제공하고 있습니다. 에서 F()작동하는 경우 에서 작동합니다 archetypes::Moveable.

Keep iterating on this idea until you've really pared down the required functionality to the bare minimum. Maybe you don't even need the archetype to be destructible? Writing archetypes is hard, but in cases like this, it's important to get right.


Long story short, right now you (I?) have to provide a specific U:

template <template <class> class HKT, class T, class U = T>
concept HKTWithTemplateMemberFunctionF {
  return requires(HKT<T> h) { // HKT<T> is a type, h is an object
    h.F(std::declval<U>()) -> HKT<U>; 
  }
}

since the compiler cannot prove for all types U that might ever exist that the member-function template will work, that is, the following is hopeless:

template <template <class> class HKT, class T>
concept HKTWithTemplateMemberFunctionF {
  return requires(HKT<T> h) {
    template<class U>  // for all those Us that haven't been written yet...
    h.F(std::declval<U>()) -> HKT<U>; 
  }
}

In an hypothetical designed-in-5-min concepts-lite implementation where we are able to constrain U just a little-bit:

template <template <class> class HKT, class T, 
          InputIterator U = InputIterator()  /* imaginary syntax */ >
concept HKTWithTemplateMemberFunctionF {
  return requires(HKT<T> h) {
      h.F(std::declval<U>()) -> HKT<U>; // Is InputIterator enough to instantiate F?
  }
}

the compiler would only need to check if a model of InputIterator is enough to instantiate h.F, which is possible even if h.F is not constrained! Additionally providing U just checks that it models InputIterator, no need to even try to check h.F for U since InputIterator is enough. This could be used to optimize compile-time performance and...

...would probably interact in surprising ways with SFINAE, since AFAIK you can have a concept-overloaded function (e.g. for InputIterator) that accepts all input iterators except that one (SFINAE! why would anyone do that?!), and thus could pass concept-checking but blow at instantiation time... sad.

참고URL : https://stackoverflow.com/questions/23659382/specifying-a-concept-for-a-type-that-has-a-member-function-template-using-concep

반응형