ユーザーが関数テンプレートパラメーターを指定して、それを推論することを強制できないようにするにはどうすればよいですか?


8

テンプレート関数があるとしましょう:

template <typename A, typename B>
A fancy_cast(B)
{
    return {};
}

使用目的はのようなものですfancy_cast<int>(1.f)

ただし、ユーザーが2番目のテンプレートパラメータを手動で指定することを妨げるものは何もありませんfancy_cast<int, int>(1.f)

typename B指定されないようにして、それを推論させるにはどうすればよいですか?

私はこれを思いつきました:

// Using this wrapper prevents the code from being
// ill-formed NDR due to [temp.res]/8.3
template <auto V> inline constexpr auto constant_value = V;

template <
    typename A,
    typename ...Dummy,
    typename B,
    typename = std::enable_if_t<constant_value<sizeof...(Dummy)> == 0>
>
A fancy_cast(B)
{
    return {};
}

それは動作するように見えますが、それは非常に面倒です。もっと良い方法はありますか?

回答:


4

fancy_cast可変テンプレートの作成についてはどうですか?

template <typename A>
struct fancy_cast_t {
    template <typename B>
    A operator()(B x) const { return x; }
};

template <typename A>
constexpr fancy_cast_t<A> fancy_cast {};

fancy_cast<int>(1.5);  // works
fancy_cast<int, int>(1.5);  // doesn't work
fancy_cast<int>.operator()<int>(1.5);  // works, but no one would do this

3

これは最も効率的なソリューションではありませんが、変換する型のテンプレートパラメーターを持つクラスを作成し、任意の型をとるコンストラクターテンプレートを作成できます。次にoperator T、型にを追加すると、クラスをインスタンス化して、正しい値を返すことができます。それは次のようになります

template<typename T>
struct fancy_cast
{
    T ret;
    template<typename U>
    fancy_cast(U u) : ret(u) {} // or whatever you want to do to convert U to T
    operator T() && { return std::move(ret); }
};

int main()
{
    double a = 0;
    int b = fancy_cast<int>(a);
}

これが機能するのは、実際には呼び出すことができないため、コンストラクターのテンプレートパラメーターを指定する方法がないためです。


2

見栄えの良いソリューションを見つけました。

ユーザーが作成できないタイプの非タイプパラメーターパックを使用できます。1たとえば、非表示クラスへの参照:

namespace impl
{
    class require_deduction_helper
    {
      protected:
        constexpr require_deduction_helper() {}
    };
}

using require_deduction = impl::require_deduction_helper &;

template <typename A, require_deduction..., typename B>
A fancy_cast(B)
{
    return {};
}

1を構築するための抜け穴を残す必要がdeduction_barrierあります。そうしないと、コードが不正なNDRになります。これが、コンストラクタが保護されている理由です。


1
M.Macドゥ@あなたはすべての可能性のために意味AB?なぜそうならないのかわかりません。
HolyBlackCat

私はあなたが必要protectedrequire_deduction...は思わない、空である必要はありません(とは反対にenable_if_t<sizeof...(Ts) == 0>)。テンプレートが無効であるのは、一部の値を構成できないからではありません。同様に、メンバーがいなくstruct S{}; using member_ptr_t = void (S::*)();ても有効ですS
Jarod42

@ Jarod42うーん。私がそれを読んだとき、この条項は、空ではないパックで有効な専門化を作成できる必要がある、またはそれが不正なNDRであると述べています。member_ptr_tで初期化できますnullptrが、それができない場合は、パラメータパックを作成できなかったと思います。
HolyBlackCat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.