2017-03-07 4 views
3

コンパイル時に空き関数が利用可能かどうかを検出するコンパクトな方法を実装しようとしています(例としてstd::maxを使用しています)。私がコメントアウトした場合(in Compiler Explorerを参照)(1)、検出が動作し、私のコードは、constexprの他の枝を使用しています無効な式が使用された場合、コンセプトをコンパイルできないのでしょうか?

#include <stdio.h> 
#include <algorithm>   // (1) 

namespace std { struct max; } // (2) 

template<typename A> 
concept bool have_std_max = requires(A const& a1, A const& a2) { 
    { std::max(a1, a2) } 
}; 

template <typename A> 
constexpr A const &my_max(A const &a1, A const &a2) { 
    if constexpr(have_std_max<A>) { 
    return std::max(a1, a2); 
    } 
    else { 
    return (a1 > a2) ? a1 : a2; 
    } 
} 

int main() { 
    int x = 5, y = 6; 
    return my_max(x, y); 
} 

:私はこれを思い付きました。ただし、(1)と(2)の両方をコメントアウトすると、std::maxという名前はコンパイラには不明なので、このコードはコンパイルできません。この場合、コンセプトは単にfalseを返してはいけませんか?ダミーを宣言することなく、同様のものを実装する方法はありますかmax

+0

あなたは修飾名 'std :: max'を使用しています。私は資格がおそらく問題だと思います! *名前空間に* name *が存在しないことを示しているので、このような呼び出しの成功はテンプレート引数 'A'に依存しないので、コンパイラは' A'を知らなくても* fail *を保証することができます。しかし、修飾されていない名前は* ADLによって*検索されるかもしれません。コンパイラは 'A'が分かった後の段階に決定を延期しなければなりません。まあ、それは私の推測で、いくつかの手作りの推論です。 – Nawaz

+0

... unqualified-nameの場合でも、名前が見つからなければ、それは*失敗するかどうか、あるいはそのコンセプトのために 'false'値になるかどうかは分かりません。 – Nawaz

+1

@Nawazそうです、私は無条件の名前で試しましたが、実際には事前の宣言なしで動作します。 –

答えて

2

C++のテンプレートシステムは、間違ったコードを書くことを決して許すものではありません。テンプレートは、いわゆる依存型のタイプと式にのみ余裕を提供します。 (in this answerより深く研究されている長いトピック)。std::maxという形式の修飾名は、何も依存しないので、でなければなりません。つまり、ルックアップは成功する必要があります。

max宣言を追加しようとすると、正しい軌道に乗っていました。これにより、依存しない修飾名は常に正常に宣言を検出します。一方、全体的な表現は(a0およびa1を含むことにより)依然として依存している。

#include <algorithm> 

namespace dirty_tricks { 

namespace max_fallback { 

// non-deducible on purpose 
template<typename Dummy> 
void max() = delete; 

} // max_fallback 

namespace lookup { 

// order of directives is not significant 
using namespace std; 
using namespace max_fallback; 

} // lookup 

} // dirty_tricks 

template<typename Val> 
concept bool have_std_max = requires(Val arg) { 
    // N.B. qualified call to avoid ADL 
    dirty_tricks::lookup::max(arg, arg); 
}; 

<algorithm>std名前空間がまだ宣言されていることを確認してください含ま除去することにより、コードをテストするか、usingディレクティブを:残っているのは、私たちがすることはできませんstd名前空間を、汚染を避けるためにありますこのColiru demoに見られるように失敗することがあります。)

を今すぐdirty_tricks::lookup::maxのみstd::maxdirty_tricks::max_fallback::maxまたは後者の両方を発見し、それが失敗することはできませんどちらか。私たちはまた、私たち自身のmax過負荷がそれを削除することによって有効な表現になることができないことを確かめます(そうしないと、有効な呼び出しはまったく異なって見えます)。

+0

ありがとう、素晴らしい説明。 –

関連する問題