5

テストケース

が組み込みデータ型である場合、関数の戻り値の型をヘッダーからauto foo(T f)呼び出す場合と同じにします。sin(f)cmathf

template <typename T>
auto foo(T f) -> decltype(sin(f))
{
    using std::sin;
    return sin(f);
}

これは壊れています。sin(f)withinはwithindecltypeで検索されないため、戻り値の型が であるバリアントstdのみが見つかります。次のプログラムは、次のことを示しています。Csin(double)double

#include <cmath>
#include <iostream>
#include <typeinfo>

namespace meh {
    struct Nanometer {};
    struct SinfulNanometer {};
    SinfulNanometer sin(Nanometer) { return SinfulNanometer(); }
}

template <typename T>
auto foo(T f) -> decltype(sin(f))
{
    using std::sin;
    std::cout << typeid(decltype(sin(f))).name() << '\n';
}


int main () {
    std::cout << typeid(decltype(foo(0.))).name() << '\n'
              << typeid(decltype(foo(0.f))).name() << '\n'
              << typeid(decltype(foo(meh::Nanometer()))).name() << '\n';
              
    foo(0.);
    foo(0.f);
    foo(meh::Nanometer());
}

出力:

d
d
N3meh15SinfulNanometerE
d
f
N3meh15SinfulNanometerE

double出力は、戻り値の型が常にfor foo->float and foo->doubleであること 示唆していfoo()ます。sin(float|double)using std::sin

そのようなケースはすでに gremium で考慮されていたのだろうかと思いますが、それは私の質問ではありません。

質問

私の質問は:

名前が inまたは ADL-looked-up のfooいずれかである関数と同じ戻り値の型を持たせるための賢明な方法は何ですか?namespace std

機能しない回避策:

template <typename T>
auto foo(T f) -> decltype(std::sin(f)); // Will miss sin(Nanometer)

標準案?

template <typename T>
auto foo(T f) -> decltype(using std::sin; sin(f));

is の順列を使用するenable_ifと、コードの自己文書化が妨げられます。enable_ifメタプログラミングの良い練習です。しかし、一見単純な機能をすばやく把握することは、正しいことではないため、保守性の精神に反します。


編集:私はdecltypeSFINAEをあまりあいまいに使用することもしていないので、新しいauto foo() {....}宣言を含むC++ 14は役に立たないかもしれません。

4

2 に答える 2