What is a niebloid? Ask Question

What is a niebloid? Ask Question

With C++20 we can read the term "niebloid" more often now in the cppreference.

On SO we can find today 2020/07/16 2 articles mentioning it:

Google does also not spit out that many results. The most prominent is maybe here.

Can somebody shed a little bit more light on niebloids?

ベストアンサー1

The term niebloid comes from Eric Niebler's name. In simple words, they are function objects that disable ADL (argument-dependent lookup) from happening so that the overloads in std:: aren't picked up when an algorithm from std::ranges is called.

Here's a tweet (from 2018) and answer from Eric himself suggesting the name. Eric wrote an article in 2014 explaining this concept.

It can best be seen in action in the standard document itself:

25.2.2
The entities defined in the std​::​ranges namespace in this Clause are not found by argument-dependent name lookup (basic.lookup.argdep). When found by unqualified (basic.lookup.unqual) name lookup for the postfix-expression in a function call, they inhibit argument-dependent name lookup.

void foo() {
  using namespace std::ranges;
  std::vector<int> vec{1,2,3};
  find(begin(vec), end(vec), 2);        // #1
}

#1の関数呼び出し式はstd​::​ranges​::​find、 (a) および から返される反復子の型がおよび に関連付けられている可能性がstd​::​findあるにもかかわらず、(b)前者では最初の 2 つのパラメータが同じ型である必要があるため、 よりも特殊化されている ([temp.func.order]) にもかかわらずbegin(vec)、ではなくを呼び出します。end(vec)namespace stdstd​::​findstd​::​ranges​::​find

上記の例では日常生活動作オフになっているため、通話は直接 に転送されますstd::ranges::find

これをさらに詳しく調べるために、小さな例を作成しましょう。

namespace mystd
{
    class B{};
    class A{};
    template<typename T>
    void swap(T &a, T &b)
    {
        std::cout << "mystd::swap\n";
    }
}

namespace sx
{
    namespace impl {
       //our functor, the niebloid
        struct __swap {
            template<typename R, typename = std::enable_if_t< std::is_same<R, mystd::A>::value >  >
            void operator()(R &a, R &b) const
            {
                std::cout << "in sx::swap()\n";
                // swap(a, b); 
            }
        };
    }
    inline constexpr impl::__swap swap{};
}

int main()
{
    mystd::B a, b;
    swap(a, b); // calls mystd::swap()

    using namespace sx;
    mystd::A c, d;
    swap(c, d); //No ADL!, calls sx::swap!

    return 0;
}

説明元cppreference:

このページで説明されている関数のようなエンティティはニーブロイドです。

  • いずれかを呼び出すときに、明示的なテンプレート引数リストを指定することはできません。
  • いずれも引数依存の検索では表示されません。
  • 関数呼び出し演算子の左側の名前の通常の非修飾検索によってそれらのいずれかが見つかった場合、引数に依存する検索は禁止されます。

ニーブロイドは関数オブジェクトであるため、引数依存検索 (ADL) には表示されません。また、ADL は関数オブジェクトではなくフリー関数に対してのみ実行されます。3 番目のポイントは、標準の例で何が起こったかです。

find(begin(vec), end(vec), 2); //unqualified call to find

への呼び出しは修飾されていないため、検索が開始されると関数オブジェクトfind()が見つかり、 ADL の実行が停止します。std::ranges::find

さらに検索してみるとこれこれは、私の意見では、ニーブロイドと CPO (カスタマイズ ポイント オブジェクト) の最も理解しやすい説明です。

... 1つの最高執行責任者オブジェクト(関数ではない)であり、呼び出し可能であり、constexpr 構築可能であり、[...] カスタマイズ可能(「プログラム定義型と対話する」という意味です)であり、概念制約があります。
[...]
上記から「カスタマイズ可能、概念に制約がある」という形容詞を取り除くと、ADLをオフにする関数オブジェクトが得られますが、必ずしもカスタマイズポイントではありません。などの C++2a Ranges アルゴリズムはstd::ranges::find次のようになります。呼び出し可能でconstexpr構築可能なオブジェクトは、口語的に「ニーブロイド」と呼ばれます。エリック・ニーブラー氏に敬意を表して。

おすすめ記事