C ++ 14 자동 반환 유형 공제는 언제 사용해야합니까?
GCC 4.8.0이 출시되면 C ++ 14의 일부인 자동 반환 유형 공제를 지원하는 컴파일러가 있습니다. 을 사용하면 다음 -std=c++1y
과 같이 할 수 있습니다.
auto foo() { //deduced to be int
return 5;
}
내 질문은 :이 기능을 언제 사용해야합니까? 언제 그리고 언제 코드를 더 깨끗하게해야합니까?
시나리오 1
내가 생각할 수있는 첫 번째 시나리오는 가능할 때마다입니다. 이런 식으로 작성할 수있는 모든 기능이 있어야합니다. 이것의 문제점은 항상 코드를 더 읽기 쉽게 만들 수는 없다는 것입니다.
시나리오 2
다음 시나리오는 더 복잡한 반환 유형을 피하는 것입니다. 매우 가벼운 예로서 :
template<typename T, typename U>
auto add(T t, U u) { //almost deduced as decltype(t + u): decltype(auto) would
return t + u;
}
나는 그것이 실제로 문제가 될 것이라고는 생각하지 않지만, 반환 유형이 매개 변수에 명시 적으로 의존하는 것이 어떤 경우에는 더 명확 할 수 있다고 생각합니다.
시나리오 3
다음으로 중복을 방지하려면
auto foo() {
std::vector<std::map<std::pair<int, double>, int>> ret;
//fill ret in with stuff
return ret;
}
C ++ 11에서는 때로는 return {5, 6, 7};
벡터 대신에 항상 작동 할 수는 있지만 항상 작동하지는 않으며 함수 헤더와 함수 본문 모두에서 유형을 지정해야합니다. 이는 순전히 중복이며, 자동 반환 유형 공제는 이러한 중복을 방지합니다.
시나리오 4
마지막으로 매우 간단한 함수 대신 사용할 수 있습니다.
auto position() {
return pos_;
}
auto area() {
return length_ * width_;
}
그러나 때로는 정확한 유형을 알고 싶을 때 함수를 볼 수 있으며, 제공되지 않으면 코드의 다른 지점으로 이동해야합니다 pos_
.
결론
이러한 시나리오를 제시하면 실제로이 기능이 코드를 더 깨끗하게 만드는 데 유용한 상황은 무엇입니까? 여기서 언급하지 않은 시나리오는 어떻습니까? 나중에 물지 않도록이 기능을 사용하기 전에 어떤 예방 조치를 취해야합니까? 이 기능이 없으면 불가능한 새로운 기능이 있습니까?
여러 질문은 이에 대한 답을 찾는 데 도움을주기위한 것입니다.
C ++ 11은 람다에서 반환 유형 공제를 사용할 때와 auto
변수 를 사용할 때와 비슷한 질문을 제기 합니다.
C와 C ++ 03의 질문에 대한 전통적인 대답은 "문 경계를 넘어서 명시 적으로 표현하는 것입니다. 표현식 내에서 일반적으로 암시 적이지만 캐스트로 명시 적으로 만들 수 있습니다". C ++ 11 및 C ++ 1y는 유형 공제 도구를 도입하여 새로운 장소에서 유형을 생략 할 수 있습니다.
죄송 합니다만 일반적인 규칙을 적용하여이 문제를 미리 해결할 수는 없습니다. 특정 코드를 살펴보고 어디에서나 유형을 지정하는 가독성에 도움이되는지 여부를 스스로 결정해야합니다. 코드에서 "이 유형은 X"라고 말하는 것이 더 낫거나 더 낫습니다. "이것의 타입은 코드의이 부분을 이해하는 것과 무관하다 : 컴파일러는 알아야하고 우리는 아마 그것을 해결할 수는 있지만 여기서 말할 필요는 없다"고 말하는가?
"가독성"은 객관적으로 정의되어 있지 않으며 [*] 독자에 따라 다양하기 때문에 스타일 가이드가 전적으로 만족할 수없는 코드의 작성자 / 편집자에게는 책임이 있습니다. 스타일 가이드가 규범을 규정하는 정도까지도, 다른 사람들은 다른 규범을 선호하고 "읽기 어려운"것으로 생소한 것을 발견하는 경향이 있습니다. 따라서 제안 된 특정 스타일 규칙의 가독성은 종종 다른 스타일 규칙의 맥락에서만 판단 할 수 있습니다.
모든 시나리오 (첫 번째조차도)는 누군가의 코딩 스타일에 사용됩니다. 개인적으로 두 번째는 가장 강력한 유스 케이스라고 생각하지만 문서 도구에 따라 달라질 것으로 예상됩니다. 함수 템플릿의 반환 유형이로 auto
문서화되어 있지만 문서화 된 것으로보고하면 decltype(t+u)
(희망적으로) 신뢰할 수있는 게시 된 인터페이스를 만드는 것으로 문서화 된 것을 보는 것이 별로 도움이되지 않습니다 .
[*] 때때로 누군가가 객관적인 측정을 시도합니다. 누구나 통계적으로 유의하고 일반적으로 적용 가능한 결과를 내놓을 정도의 적은 정도로, "읽을 수있는"것에 대한 저자의 본능에 찬성하여 일하는 프로그래머에 의해 완전히 무시됩니다.
Generally speaking, the function return type is of great help to document a function. The user will know what is expected. However, there is one case where I think it could be nice to drop that return type to avoid redundancy. Here is an example:
template<typename F, typename Tuple, int... I>
auto
apply_(F&& f, Tuple&& args, int_seq<I...>) ->
decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...))
{
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...);
}
template<typename F, typename Tuple,
typename Indices = make_int_seq<std::tuple_size<Tuple>::value>>
auto
apply(F&& f, Tuple&& args) ->
decltype(apply_(std::forward<F>(f), std::forward<Tuple>(args), Indices()))
{
return apply_(std::forward<F>(f), std::forward<Tuple>(args), Indices());
}
This example is taken from the official committee paper N3493. The purpose of the function apply
is to forward the elements of a std::tuple
to a function and return the result. The int_seq
and make_int_seq
are only part of the implementation, and will probably only confuse any user trying to understand what it does.
As you can see, the return type is nothing more than a decltype
of the returned expression. Moreover, apply_
not being meant to be seen by the users, I am not sure of the usefulness of documenting its return type when it's more or less the same as apply
's one. I think that, in this particular case, dropping the return type makes the function more readable. Note that this very return type has actually been dropped and replaced by decltype(auto)
in the proposal to add apply
to the standard, N3915 (also note that my original answer predates this paper):
template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>) {
return forward<F>(f)(get<I>(forward<Tuple>(t))...);
}
template <typename F, typename Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
using Indices = make_index_sequence<tuple_size<decay_t<Tuple>>::value>;
return apply_impl(forward<F>(f), forward<Tuple>(t), Indices{});
}
However, most of the time, it is better to keep that return type. In the particular case that I described above, the return type is rather unreadable and a potential user won't gain anything from knowing it. A good documentation with examples will be far more useful.
Another thing that hasn't been mentioned yet: while declype(t+u)
allows to use expression SFINAE, decltype(auto)
does not (even though there is a proposal to change this behaviour). Take for example a foobar
function that will call a type's foo
member function if it exists or call the type's bar
member function if it exists, and assume that a class always has exacty foo
or bar
but neither both at once:
struct X
{
void foo() const { std::cout << "foo\n"; }
};
struct Y
{
void bar() const { std::cout << "bar\n"; }
};
template<typename C>
auto foobar(const C& c) -> decltype(c.foo())
{
return c.foo();
}
template<typename C>
auto foobar(const C& c) -> decltype(c.bar())
{
return c.bar();
}
Calling foobar
on an instance of X
will display foo
while calling foobar
on an instance of Y
will display bar
. If you use the automatic return type deduction instead (with or without decltype(auto)
), you won't get expression SFINAE and calling foobar
on an instance of either X
or Y
will trigger a compile-time error.
It's never necessary. As to when you should- you're going to get a lot of different answers about that. I'd say not at all until its actually an accepted part of the standard and well supported by the majority of major compilers in the same way.
Beyond that, its going to be a religious argument. I'd personally say never- putting in the actual return type makes code clearer, is far easier for maintenance (I can look at a function's signature and know what it returns vs actually having to read the code), and it removes the possibility that you think it should return one type and the compiler thinks another causing problems (as has happened with every scripting language I've ever used). I think auto was a giant mistake and it will cause orders of magnitude more pain than help. Others will say you should use it all the time, as it fits their philosophy of programming. At any rate, this is way out of scope for this site.
It's got nothing to do with the simplicity of the function (as a now-deleted duplicate of this question supposed).
Either the return type is fixed (don't use auto
), or dependent in a complex way on a template parameter (use auto
in most cases, paired with decltype
when there are multiple return points).
Consider a real production environment: many functions and unit tests all interdependent on the return type of foo()
. Now suppose that the return type needs to change for whatever reason.
If the return type is auto
everywhere, and callers to foo()
and related functions use auto
when getting the returned value, the changes that need to be made are minimal. If not, this could mean hours of extremely tedious and error-prone work.
As a real-world example, I was asked to change a module from using raw pointers everywhere to smart pointers. Fixing the unit tests was more painful than the actual code.
While there are other ways this could be handled, the use of auto
return types seems like a good fit.
I want to provide an example where return type auto is perfect:
Imagine you want to create a short alias for a long subsequent function call. With auto you don't need to take care of the original return type (maybe it will change in future) and the user can click the original function to get the real return type:
inline auto CreateEntity() { return GetContext()->GetEntityManager()->CreateEntity(); }
PS: Depends on this question.
For scenario 3 I would turn the return type of function signature with the local variable to be returned around. It would make it clearer for client programmers hat the function returns. Like this:
Scenario 3 To prevent redundancy:
std::vector<std::map<std::pair<int, double>, int>> foo() {
decltype(foo()) ret;
return ret;
}
Yes, it has no auto keyword but the principal is the same to prevent redundancy and give programmers who dont have access to the source an easier time.
참고URL : https://stackoverflow.com/questions/15737223/when-should-i-use-c14-automatic-return-type-deduction
'Programming' 카테고리의 다른 글
Java 8 스트림과 RxJava 옵저버 블의 차이점 (0) | 2020.06.27 |
---|---|
Spring MVC @PathVariable가 잘림 (0) | 2020.06.27 |
Java 용 SQL 파서 라이브러리 (0) | 2020.06.24 |
영어 단어 데이터베이스를 얻는 방법? (0) | 2020.06.24 |
Apple Appstore에서 특정 앱의 다운로드 수 찾기 (0) | 2020.06.24 |