问题
Consider this little code snippet
namespace nsp
{
template<typename T>
concept Addable= requires(const T& a,const T& b)
{
{a + b} -> std::convertible_to<T>;
};
template<Addable T>
struct C
{
C();
};
}
template<nsp::Addable T>
nsp::C<T>::C() {};
As shown here GCC (10.2) and clang (11.0) accept the code while MSVC (x86 19.28) rejects it with the error message:
error C3855: 'nsp::C<T>': template parameter 'T' is incompatible with the declaration.
Is this a MSVC bug or are GCC and clang wrong accepting it? Or alternatively, did I something stupid? If I move the out-of-line definition into the namespace nsp
it seems to work for MSVC, as well. See this example.
回答1:
This behavior is an observable deviation in MSVC that has been seen usually in the context of templates and SFINAE. MSVC tends to have difficulty with out-of-line definitions of templates that have qualifications when the declarations are not qualified (from being in the same namespace). I've often encountered this when dealing with forms of SFINAE, and it appears this must be also occurring with concept
s now too.
For example, MSVC rejects the valid code:
namespace nsp {
template <typename T>
using is_convertible_to_bool = std::is_convertible<T, bool>;
template <typename T, std::enable_if_t<is_convertible_to_bool<T>::value,int> = 0>
void example(const T& x);
} // namespace nsp
template <typename T, std::enable_if_t<nsp::is_convertible_to_bool<T>::value,int>>
void nsp::example(const T& x)
{
}
Live Example
However, MSVC will accept the same code, provided you add qualifications on the is_convertible_to_bool
from namespace nsp
:
template <typename T, std::enable_if_t<nsp::is_convertible_to_bool<T>::value,int> = 0>
// ^~~~~ fixes it
void example(const T& x);
Live example
Similarly, your code sample actually works if you change the definition of struct C
to include the fully qualified concept name:
template<nsp::Addable T>
// ^~~~~
// Qualifying here fixes the failure in MSVC
struct C
{
C();
};
Live Example
I don't have time to check the standard for lookup rules for which compiler is correct (will do this later if no other answer appears), but my expectation is actually that MSVC is providing incorrect behavior. The basic name lookup should select the same type in both definitions, and thus the code should be well-formed.
来源:https://stackoverflow.com/questions/65702336/c20-concepts-out-of-line-definition-fails-with-msvc-but-not-in-gcc-or-clang