Convert EnableIfIsOStream to a concept.
Change the `EnableIfIsOstream` machinery to use a `concept` and update
usages to `requires` statements.
Change-Id: I211a42adc170ef8b31f2f3908c58810f834aaadd
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/239034
Auto-Submit: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/api/common/binding_point.h b/src/tint/api/common/binding_point.h
index e5040b8..f6110d4 100644
--- a/src/tint/api/common/binding_point.h
+++ b/src/tint/api/common/binding_point.h
@@ -81,7 +81,8 @@
/// @param o the stream to write to
/// @param bp the BindingPoint
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const BindingPoint& bp) {
return o << "[group: " << bp.group << ", binding: " << bp.binding << "]";
}
diff --git a/src/tint/cmd/common/helper.cc b/src/tint/cmd/common/helper.cc
index 1767240..8d7a09f 100644
--- a/src/tint/cmd/common/helper.cc
+++ b/src/tint/cmd/common/helper.cc
@@ -65,7 +65,8 @@
/// @param out the stream to write to
/// @param value the InputFormat
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, InputFormat value) {
switch (value) {
case InputFormat::kUnknown:
diff --git a/src/tint/lang/core/access.h b/src/tint/lang/core/access.h
index ca40a9d..43fd170 100644
--- a/src/tint/lang/core/access.h
+++ b/src/tint/lang/core/access.h
@@ -59,7 +59,8 @@
/// @param out the stream to write to
/// @param value the Access
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Access value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/address_space.h b/src/tint/lang/core/address_space.h
index b6fde43..8a79826 100644
--- a/src/tint/lang/core/address_space.h
+++ b/src/tint/lang/core/address_space.h
@@ -65,7 +65,8 @@
/// @param out the stream to write to
/// @param value the AddressSpace
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, AddressSpace value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/attribute.h b/src/tint/lang/core/attribute.h
index 640f76f..9d5d618 100644
--- a/src/tint/lang/core/attribute.h
+++ b/src/tint/lang/core/attribute.h
@@ -76,7 +76,8 @@
/// @param out the stream to write to
/// @param value the Attribute
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Attribute value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/binary_op.h b/src/tint/lang/core/binary_op.h
index d6f558b..c73416d 100644
--- a/src/tint/lang/core/binary_op.h
+++ b/src/tint/lang/core/binary_op.h
@@ -61,7 +61,8 @@
/// @param out the stream to write to
/// @param value the BinaryOp
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, BinaryOp value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/builtin_fn.h b/src/tint/lang/core/builtin_fn.h
index 4491b5a..76aed36 100644
--- a/src/tint/lang/core/builtin_fn.h
+++ b/src/tint/lang/core/builtin_fn.h
@@ -211,7 +211,8 @@
/// Emits the name of the builtin function type. The spelling, including case,
/// matches the name in the WGSL spec.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/core/builtin_fn.h.tmpl b/src/tint/lang/core/builtin_fn.h.tmpl
index 6f4ee9f..a18e010 100644
--- a/src/tint/lang/core/builtin_fn.h.tmpl
+++ b/src/tint/lang/core/builtin_fn.h.tmpl
@@ -44,7 +44,8 @@
/// Emits the name of the builtin function type. The spelling, including case,
/// matches the name in the WGSL spec.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/core/builtin_type.h b/src/tint/lang/core/builtin_type.h
index 5497b5b..3484c4b 100644
--- a/src/tint/lang/core/builtin_type.h
+++ b/src/tint/lang/core/builtin_type.h
@@ -155,7 +155,8 @@
/// @param out the stream to write to
/// @param value the BuiltinType
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, BuiltinType value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/builtin_value.h b/src/tint/lang/core/builtin_value.h
index 12fa562..95ce822 100644
--- a/src/tint/lang/core/builtin_value.h
+++ b/src/tint/lang/core/builtin_value.h
@@ -72,7 +72,8 @@
/// @param out the stream to write to
/// @param value the BuiltinValue
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, BuiltinValue value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/interpolation_sampling.h b/src/tint/lang/core/interpolation_sampling.h
index 4dde2ce..f01c85b 100644
--- a/src/tint/lang/core/interpolation_sampling.h
+++ b/src/tint/lang/core/interpolation_sampling.h
@@ -61,7 +61,8 @@
/// @param out the stream to write to
/// @param value the InterpolationSampling
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, InterpolationSampling value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/interpolation_type.h b/src/tint/lang/core/interpolation_type.h
index c05024d..7b834ff 100644
--- a/src/tint/lang/core/interpolation_type.h
+++ b/src/tint/lang/core/interpolation_type.h
@@ -59,7 +59,8 @@
/// @param out the stream to write to
/// @param value the InterpolationType
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, InterpolationType value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/intrinsic/ctor_conv.h b/src/tint/lang/core/intrinsic/ctor_conv.h
index 84bbca6..948f12f 100644
--- a/src/tint/lang/core/intrinsic/ctor_conv.h
+++ b/src/tint/lang/core/intrinsic/ctor_conv.h
@@ -77,7 +77,8 @@
/// @param o the stream to write to
/// @param c the CtorConv
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, CtorConv c) {
return o << str(c);
}
diff --git a/src/tint/lang/core/intrinsic/ctor_conv.h.tmpl b/src/tint/lang/core/intrinsic/ctor_conv.h.tmpl
index a59b6ad..d86fe92 100644
--- a/src/tint/lang/core/intrinsic/ctor_conv.h.tmpl
+++ b/src/tint/lang/core/intrinsic/ctor_conv.h.tmpl
@@ -39,7 +39,8 @@
/// @param o the stream to write to
/// @param c the CtorConv
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, CtorConv c) {
return o << str(c);
}
diff --git a/src/tint/lang/core/ir/function.h b/src/tint/lang/core/ir/function.h
index 8a91f13..8223599 100644
--- a/src/tint/lang/core/ir/function.h
+++ b/src/tint/lang/core/ir/function.h
@@ -243,7 +243,8 @@
/// @param out the stream to write to
/// @param value the Function::PipelineStage
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Function::PipelineStage value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/number.h b/src/tint/lang/core/number.h
index 4080afa..59f700f 100644
--- a/src/tint/lang/core/number.h
+++ b/src/tint/lang/core/number.h
@@ -191,7 +191,8 @@
/// @param out the stream to write to
/// @param num the Number
/// @return the stream so calls can be chained
-template <typename STREAM, typename T, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename T>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Number<T> num) {
return out << num.value;
}
@@ -344,7 +345,8 @@
/// @param out the stream to write to
/// @param failure the ConversionFailure
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, ConversionFailure failure) {
switch (failure) {
case ConversionFailure::kExceedsPositiveLimit:
diff --git a/src/tint/lang/core/parameter_usage.h b/src/tint/lang/core/parameter_usage.h
index f9f3fbc..1bbb9c2 100644
--- a/src/tint/lang/core/parameter_usage.h
+++ b/src/tint/lang/core/parameter_usage.h
@@ -104,7 +104,8 @@
/// @param out the stream to write to
/// @param value the ParameterUsage
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, ParameterUsage value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/parameter_usage.h.tmpl b/src/tint/lang/core/parameter_usage.h.tmpl
index 3b74773..79f9890 100644
--- a/src/tint/lang/core/parameter_usage.h.tmpl
+++ b/src/tint/lang/core/parameter_usage.h.tmpl
@@ -39,7 +39,8 @@
/// @param out the stream to write to
/// @param value the ParameterUsage
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, ParameterUsage value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/subgroup_matrix_kind.h b/src/tint/lang/core/subgroup_matrix_kind.h
index ef67888..aa188c6 100644
--- a/src/tint/lang/core/subgroup_matrix_kind.h
+++ b/src/tint/lang/core/subgroup_matrix_kind.h
@@ -59,7 +59,8 @@
/// @param out the stream to write to
/// @param value the SubgroupMatrixKind
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, SubgroupMatrixKind value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/texel_format.h b/src/tint/lang/core/texel_format.h
index dd28dc6..b0b1579 100644
--- a/src/tint/lang/core/texel_format.h
+++ b/src/tint/lang/core/texel_format.h
@@ -73,7 +73,8 @@
/// @param out the stream to write to
/// @param value the TexelFormat
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, TexelFormat value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/core/type/sampler_kind.h b/src/tint/lang/core/type/sampler_kind.h
index 4caffce..6c517b2 100644
--- a/src/tint/lang/core/type/sampler_kind.h
+++ b/src/tint/lang/core/type/sampler_kind.h
@@ -48,7 +48,8 @@
/// @param out the stream to write to
/// @param kind the SamplerKind
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, SamplerKind kind) {
return out << ToString(kind);
}
diff --git a/src/tint/lang/core/type/texture_dimension.h b/src/tint/lang/core/type/texture_dimension.h
index 7b5b486..0fb37b7 100644
--- a/src/tint/lang/core/type/texture_dimension.h
+++ b/src/tint/lang/core/type/texture_dimension.h
@@ -58,7 +58,8 @@
/// @param out the stream to write to
/// @param dim the type::TextureDimension
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, core::type::TextureDimension dim) {
return out << ToString(dim);
}
diff --git a/src/tint/lang/core/unary_op.h b/src/tint/lang/core/unary_op.h
index 72c72f9..b1bab65 100644
--- a/src/tint/lang/core/unary_op.h
+++ b/src/tint/lang/core/unary_op.h
@@ -49,7 +49,8 @@
/// @param out the stream to write to
/// @param value the UnaryOp
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, UnaryOp value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/glsl/builtin_fn.h b/src/tint/lang/glsl/builtin_fn.h
index 95a5c1c..b99ab78 100644
--- a/src/tint/lang/glsl/builtin_fn.h
+++ b/src/tint/lang/glsl/builtin_fn.h
@@ -98,7 +98,8 @@
const char* str(BuiltinFn i);
/// Emits the name of the builtin function type.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/glsl/builtin_fn.h.tmpl b/src/tint/lang/glsl/builtin_fn.h.tmpl
index edbf0ee..91a6786 100644
--- a/src/tint/lang/glsl/builtin_fn.h.tmpl
+++ b/src/tint/lang/glsl/builtin_fn.h.tmpl
@@ -37,7 +37,8 @@
const char* str(BuiltinFn i);
/// Emits the name of the builtin function type.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/hlsl/builtin_fn.h b/src/tint/lang/hlsl/builtin_fn.h
index c89507c..d910303 100644
--- a/src/tint/lang/hlsl/builtin_fn.h
+++ b/src/tint/lang/hlsl/builtin_fn.h
@@ -113,7 +113,8 @@
const char* str(BuiltinFn i);
/// Emits the name of the builtin function type.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/hlsl/builtin_fn.h.tmpl b/src/tint/lang/hlsl/builtin_fn.h.tmpl
index 6160d6e..c2f0dd5 100644
--- a/src/tint/lang/hlsl/builtin_fn.h.tmpl
+++ b/src/tint/lang/hlsl/builtin_fn.h.tmpl
@@ -37,7 +37,8 @@
const char* str(BuiltinFn i);
/// Emits the name of the builtin function type.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/msl/builtin_fn.h b/src/tint/lang/msl/builtin_fn.h
index 99a735e..e847cc8 100644
--- a/src/tint/lang/msl/builtin_fn.h
+++ b/src/tint/lang/msl/builtin_fn.h
@@ -94,7 +94,8 @@
const char* str(BuiltinFn i);
/// Emits the name of the builtin function type.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/msl/builtin_fn.h.tmpl b/src/tint/lang/msl/builtin_fn.h.tmpl
index deb288c..b8e6c6b 100644
--- a/src/tint/lang/msl/builtin_fn.h.tmpl
+++ b/src/tint/lang/msl/builtin_fn.h.tmpl
@@ -37,7 +37,8 @@
const char* str(BuiltinFn i);
/// Emits the name of the builtin function type.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/spirv/builtin_fn.h b/src/tint/lang/spirv/builtin_fn.h
index 9e41fbb..6daede2 100644
--- a/src/tint/lang/spirv/builtin_fn.h
+++ b/src/tint/lang/spirv/builtin_fn.h
@@ -150,7 +150,8 @@
/// Emits the name of the builtin function type. The spelling, including case,
/// matches the name in the WGSL spec.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/spirv/builtin_fn.h.tmpl b/src/tint/lang/spirv/builtin_fn.h.tmpl
index 157542e..0fef8a4 100644
--- a/src/tint/lang/spirv/builtin_fn.h.tmpl
+++ b/src/tint/lang/spirv/builtin_fn.h.tmpl
@@ -39,7 +39,8 @@
/// Emits the name of the builtin function type. The spelling, including case,
/// matches the name in the WGSL spec.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/spirv/reader/ast_parser/construct.h b/src/tint/lang/spirv/reader/ast_parser/construct.h
index 1a17063..f497f9b 100644
--- a/src/tint/lang/spirv/reader/ast_parser/construct.h
+++ b/src/tint/lang/spirv/reader/ast_parser/construct.h
@@ -197,7 +197,8 @@
/// @param o the stream
/// @param c the structured construct
/// @returns the stream
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const Construct& c) {
o << "Construct{ " << ToString(c.kind) << " [" << c.begin_pos << "," << c.end_pos << ")"
<< " begin_id:" << c.begin_id << " end_id:" << c.end_id << " depth:" << c.depth;
@@ -229,7 +230,8 @@
/// @param o the stream
/// @param c the structured construct
/// @returns the stream
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const std::unique_ptr<Construct>& c) {
return o << *(c.get());
}
@@ -261,7 +263,8 @@
/// @param o the stream
/// @param cl the construct list
/// @returns the stream
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const ConstructList& cl) {
o << "ConstructList{\n";
for (const auto& c : cl) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.h b/src/tint/lang/spirv/reader/ast_parser/function.h
index 5ac2cf0..d876621 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.h
+++ b/src/tint/lang/spirv/reader/ast_parser/function.h
@@ -196,7 +196,8 @@
/// @param o the stream
/// @param bi the BlockInfo
/// @returns the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const BlockInfo& bi) {
o << "BlockInfo{" << " id: " << bi.id << " pos: " << bi.pos
<< " merge_for_header: " << bi.merge_for_header
@@ -372,7 +373,8 @@
/// @param o the stream
/// @param di the DefInfo
/// @returns the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const DefInfo& di) {
o << "DefInfo{" << " inst.result_id: " << di.inst.result_id();
if (di.local.has_value()) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/usage.h b/src/tint/lang/spirv/reader/ast_parser/usage.h
index 9cfd116..1105999 100644
--- a/src/tint/lang/spirv/reader/ast_parser/usage.h
+++ b/src/tint/lang/spirv/reader/ast_parser/usage.h
@@ -144,7 +144,8 @@
/// @param out the stream
/// @param u the Usage
/// @returns the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Usage& u) {
return u.operator<<(out);
}
diff --git a/src/tint/lang/spirv/writer/common/helper_test.h b/src/tint/lang/spirv/writer/common/helper_test.h
index 68949cb..4b419a3 100644
--- a/src/tint/lang/spirv/writer/common/helper_test.h
+++ b/src/tint/lang/spirv/writer/common/helper_test.h
@@ -58,7 +58,8 @@
kF32,
kF16,
};
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, TestElementType type) {
switch (type) {
case kBool:
diff --git a/src/tint/lang/spirv/writer/texture_builtin_test.cc b/src/tint/lang/spirv/writer/texture_builtin_test.cc
index fb70af2..37878a4 100644
--- a/src/tint/lang/spirv/writer/texture_builtin_test.cc
+++ b/src/tint/lang/spirv/writer/texture_builtin_test.cc
@@ -79,7 +79,8 @@
Vector<const char*, 2> instructions;
};
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, TextureType type) {
switch (type) {
case kSampledTexture:
diff --git a/src/tint/lang/wgsl/ast/binary_expression.h b/src/tint/lang/wgsl/ast/binary_expression.h
index 2d49aca..5432079 100644
--- a/src/tint/lang/wgsl/ast/binary_expression.h
+++ b/src/tint/lang/wgsl/ast/binary_expression.h
@@ -287,7 +287,8 @@
/// @param out the stream to write to
/// @param op the core::BinaryOp
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, core::BinaryOp op) {
out << FriendlyName(op);
return out;
diff --git a/src/tint/lang/wgsl/ast/float_literal_expression.h b/src/tint/lang/wgsl/ast/float_literal_expression.h
index db30537..0dca762 100644
--- a/src/tint/lang/wgsl/ast/float_literal_expression.h
+++ b/src/tint/lang/wgsl/ast/float_literal_expression.h
@@ -77,7 +77,8 @@
/// @param out the stream to write to
/// @param suffix the suffix to write
/// @returns out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, FloatLiteralExpression::Suffix suffix) {
return out << ToString(suffix);
}
diff --git a/src/tint/lang/wgsl/ast/int_literal_expression.h b/src/tint/lang/wgsl/ast/int_literal_expression.h
index c95d25d..b77c6c4 100644
--- a/src/tint/lang/wgsl/ast/int_literal_expression.h
+++ b/src/tint/lang/wgsl/ast/int_literal_expression.h
@@ -76,7 +76,8 @@
/// @param out the stream to write to
/// @param suffix the suffix to write
/// @returns out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, IntLiteralExpression::Suffix suffix) {
return out << ToString(suffix);
}
diff --git a/src/tint/lang/wgsl/ast/pipeline_stage.h b/src/tint/lang/wgsl/ast/pipeline_stage.h
index 595e4ae..683213c 100644
--- a/src/tint/lang/wgsl/ast/pipeline_stage.h
+++ b/src/tint/lang/wgsl/ast/pipeline_stage.h
@@ -43,7 +43,8 @@
/// @param out the stream to write to
/// @param stage the PipelineStage
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, PipelineStage stage) {
return out << ToString(stage);
}
diff --git a/src/tint/lang/wgsl/builtin_fn.h b/src/tint/lang/wgsl/builtin_fn.h
index d420455..d752c23 100644
--- a/src/tint/lang/wgsl/builtin_fn.h
+++ b/src/tint/lang/wgsl/builtin_fn.h
@@ -214,7 +214,8 @@
/// Emits the name of the builtin function type. The spelling, including case,
/// matches the name in the WGSL spec.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/wgsl/builtin_fn.h.tmpl b/src/tint/lang/wgsl/builtin_fn.h.tmpl
index 68dc28d..be29cf2 100644
--- a/src/tint/lang/wgsl/builtin_fn.h.tmpl
+++ b/src/tint/lang/wgsl/builtin_fn.h.tmpl
@@ -44,7 +44,8 @@
/// Emits the name of the builtin function type. The spelling, including case,
/// matches the name in the WGSL spec.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, BuiltinFn i) {
return o << str(i);
}
diff --git a/src/tint/lang/wgsl/diagnostic_rule.h b/src/tint/lang/wgsl/diagnostic_rule.h
index 98e2f55..b6d3efb 100644
--- a/src/tint/lang/wgsl/diagnostic_rule.h
+++ b/src/tint/lang/wgsl/diagnostic_rule.h
@@ -58,7 +58,8 @@
/// @param out the stream to write to
/// @param value the CoreDiagnosticRule
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, CoreDiagnosticRule value) {
return out << ToString(value);
}
@@ -87,7 +88,8 @@
/// @param out the stream to write to
/// @param value the ChromiumDiagnosticRule
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, ChromiumDiagnosticRule value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/wgsl/diagnostic_severity.h b/src/tint/lang/wgsl/diagnostic_severity.h
index df2a49f..75d6bd6 100644
--- a/src/tint/lang/wgsl/diagnostic_severity.h
+++ b/src/tint/lang/wgsl/diagnostic_severity.h
@@ -62,7 +62,8 @@
/// @param out the stream to write to
/// @param value the DiagnosticSeverity
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, DiagnosticSeverity value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/wgsl/extension.h b/src/tint/lang/wgsl/extension.h
index 46f6d3c..ae4192b 100644
--- a/src/tint/lang/wgsl/extension.h
+++ b/src/tint/lang/wgsl/extension.h
@@ -66,7 +66,8 @@
/// @param out the stream to write to
/// @param value the Extension
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Extension value) {
return out << ToString(value);
}
diff --git a/src/tint/lang/wgsl/intrinsic/ctor_conv.h b/src/tint/lang/wgsl/intrinsic/ctor_conv.h
index 253c1b4..463859d 100644
--- a/src/tint/lang/wgsl/intrinsic/ctor_conv.h
+++ b/src/tint/lang/wgsl/intrinsic/ctor_conv.h
@@ -73,7 +73,8 @@
/// @param o the stream to write to
/// @param c the CtorConv
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, CtorConv c) {
return o << str(c);
}
diff --git a/src/tint/lang/wgsl/intrinsic/ctor_conv.h.tmpl b/src/tint/lang/wgsl/intrinsic/ctor_conv.h.tmpl
index 9ec7728..d00e6ed 100644
--- a/src/tint/lang/wgsl/intrinsic/ctor_conv.h.tmpl
+++ b/src/tint/lang/wgsl/intrinsic/ctor_conv.h.tmpl
@@ -38,7 +38,8 @@
/// @param o the stream to write to
/// @param c the CtorConv
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, CtorConv c) {
return o << str(c);
}
diff --git a/src/tint/lang/wgsl/reader/parser/token.h b/src/tint/lang/wgsl/reader/parser/token.h
index 1a8a4f8..e6b1d21 100644
--- a/src/tint/lang/wgsl/reader/parser/token.h
+++ b/src/tint/lang/wgsl/reader/parser/token.h
@@ -370,7 +370,8 @@
std::variant<int64_t, double, std::string, std::string_view> value_;
};
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Token::Type type) {
out << Token::TypeToName(type);
return out;
diff --git a/src/tint/lang/wgsl/resolver/builtin_test.cc b/src/tint/lang/wgsl/resolver/builtin_test.cc
index 4aa6ed6..1992be6 100644
--- a/src/tint/lang/wgsl/resolver/builtin_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtin_test.cc
@@ -2161,7 +2161,8 @@
namespace texture_builtin_tests {
enum class Texture { kF32, kI32, kU32 };
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Texture data) {
if (data == Texture::kF32) {
out << "f32";
diff --git a/src/tint/lang/wgsl/resolver/resolver_helper_test.h b/src/tint/lang/wgsl/resolver/resolver_helper_test.h
index afe3b37..e2b4282 100644
--- a/src/tint/lang/wgsl/resolver/resolver_helper_test.h
+++ b/src/tint/lang/wgsl/resolver/resolver_helper_test.h
@@ -187,7 +187,8 @@
/// @param out the stream to write to
/// @param s the Scalar
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
STREAM& operator<<(STREAM& out, const Scalar& s) {
std::visit([&](auto&& v) { out << v; }, s.value);
return out;
diff --git a/src/tint/lang/wgsl/sem/behavior.h b/src/tint/lang/wgsl/sem/behavior.h
index ffb0b79..987c851 100644
--- a/src/tint/lang/wgsl/sem/behavior.h
+++ b/src/tint/lang/wgsl/sem/behavior.h
@@ -53,7 +53,8 @@
/// @param out the stream to write to
/// @param behavior the Behavior to write
/// @returns out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Behavior behavior) {
return out << ToString(behavior);
}
diff --git a/src/tint/lang/wgsl/sem/sampler_texture_pair.h b/src/tint/lang/wgsl/sem/sampler_texture_pair.h
index 5388604..5ab5433 100644
--- a/src/tint/lang/wgsl/sem/sampler_texture_pair.h
+++ b/src/tint/lang/wgsl/sem/sampler_texture_pair.h
@@ -75,7 +75,8 @@
/// @param o the stream to write to
/// @param stp the SamplerTexturePair
/// @return the stream so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const SamplerTexturePair& stp) {
return o << "[sampler: " << stp.sampler_binding_point
<< ", texture: " << stp.sampler_binding_point << "]";
diff --git a/src/tint/utils/containers/enum_set.h b/src/tint/utils/containers/enum_set.h
index dec7156..54443b8 100644
--- a/src/tint/utils/containers/enum_set.h
+++ b/src/tint/utils/containers/enum_set.h
@@ -256,7 +256,8 @@
/// @param out the stream to write to
/// @param set the EnumSet to write
/// @returns out so calls can be chained
-template <typename STREAM, typename ENUM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename ENUM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, EnumSet<ENUM> set) {
out << "{";
bool first = true;
diff --git a/src/tint/utils/containers/hashmap.h b/src/tint/utils/containers/hashmap.h
index df1ed08..14c4492 100644
--- a/src/tint/utils/containers/hashmap.h
+++ b/src/tint/utils/containers/hashmap.h
@@ -71,10 +71,8 @@
/// @param out the stream to write to
/// @param key_value the HashmapEntry to write
/// @returns out so calls can be chained
-template <typename STREAM,
- typename KEY,
- typename VALUE,
- typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename KEY, typename VALUE>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const HashmapEntry<KEY, VALUE>& key_value) {
return out << "[" << key_value.key << ": " << key_value.value << "]";
}
@@ -346,13 +344,8 @@
/// @param out the stream to write to
/// @param map the Hashmap to write
/// @returns out so calls can be chained
-template <typename STREAM,
- typename KEY,
- typename VALUE,
- size_t N,
- typename HASH,
- typename EQUAL,
- typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename KEY, typename VALUE, size_t N, typename HASH, typename EQUAL>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Hashmap<KEY, VALUE, N, HASH, EQUAL>& map) {
out << "Hashmap{";
bool first = true;
diff --git a/src/tint/utils/containers/hashmap_base.h b/src/tint/utils/containers/hashmap_base.h
index 5a4a3b6..979fda2 100644
--- a/src/tint/utils/containers/hashmap_base.h
+++ b/src/tint/utils/containers/hashmap_base.h
@@ -161,7 +161,8 @@
/// @param out the stream to write to
/// @param key the HashmapKey to write
/// @returns out so calls can be chained
-template <typename STREAM, typename T, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename T>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const HashmapKey<T>& key) {
if constexpr (traits::HasOperatorShiftLeft<STREAM, T>) {
return out << key.Value();
diff --git a/src/tint/utils/containers/vector.h b/src/tint/utils/containers/vector.h
index dc5a4a0..18588d3 100644
--- a/src/tint/utils/containers/vector.h
+++ b/src/tint/utils/containers/vector.h
@@ -291,7 +291,8 @@
/// @param out the stream to write to
/// @param it the VectorIterator
/// @returns @p out so calls can be chained
-template <typename STREAM, typename T, bool FORWARD, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename T, bool FORWARD>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const VectorIterator<T, FORWARD>& it) {
return out << *it;
}
@@ -1245,7 +1246,8 @@
/// @param o the stream to write to
/// @param vec the vector
/// @return the stream so calls can be chained
-template <typename STREAM, typename T, size_t N, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename T, size_t N>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const Vector<T, N>& vec) {
o << "[";
bool first = true;
@@ -1264,7 +1266,8 @@
/// @param o the stream to write to
/// @param vec the vector reference
/// @return the stream so calls can be chained
-template <typename STREAM, typename T, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename T>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, VectorRef<T> vec) {
o << "[";
bool first = true;
diff --git a/src/tint/utils/diagnostic/diagnostic.h b/src/tint/utils/diagnostic/diagnostic.h
index 8c333d6..ede8c38 100644
--- a/src/tint/utils/diagnostic/diagnostic.h
+++ b/src/tint/utils/diagnostic/diagnostic.h
@@ -249,7 +249,8 @@
/// @param out the output stream
/// @param failure the Failure
/// @returns the output stream
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Failure& failure) {
return out << failure.reason.Str();
}
@@ -258,7 +259,8 @@
/// @param out the output stream
/// @param list the list to emit
/// @returns the output stream
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const List& list) {
return out << list.Str();
}
diff --git a/src/tint/utils/diagnostic/source.h b/src/tint/utils/diagnostic/source.h
index 3336f3a..4747ddd 100644
--- a/src/tint/utils/diagnostic/source.h
+++ b/src/tint/utils/diagnostic/source.h
@@ -242,7 +242,8 @@
/// @param out the stream to write to
/// @param loc the location to write
/// @returns out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Source::Location& loc) {
return out << loc.line << ":" << loc.column;
}
@@ -251,7 +252,8 @@
/// @param out the stream to write to
/// @param range the range to write
/// @returns out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Source::Range& range) {
return out << "[" << range.begin << ", " << range.end << "]";
}
@@ -260,7 +262,8 @@
/// @param out the stream to write to
/// @param source the source to write
/// @returns out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Source& source) {
return out << ToString(source);
}
@@ -269,7 +272,8 @@
/// @param out the stream to write to
/// @param content the file content to write
/// @returns out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Source::FileContent& content) {
return out << content.data;
}
diff --git a/src/tint/utils/generation_id.h b/src/tint/utils/generation_id.h
index 982d915..238360f 100644
--- a/src/tint/utils/generation_id.h
+++ b/src/tint/utils/generation_id.h
@@ -84,7 +84,8 @@
/// @param out the stream to write to
/// @param id the generation identifier to write
/// @returns out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, GenerationID id) {
out << "Generation<" << id.Value() << ">";
return out;
diff --git a/src/tint/utils/result.h b/src/tint/utils/result.h
index 5aa594b..1f07a6c 100644
--- a/src/tint/utils/result.h
+++ b/src/tint/utils/result.h
@@ -60,7 +60,8 @@
/// @param out the output stream
/// @param failure the Failure
/// @returns the output stream
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Failure& failure) {
return out << failure.reason;
}
@@ -217,10 +218,8 @@
/// @param out the stream to write to
/// @param res the result
/// @return the stream so calls can be chained
-template <typename STREAM,
- typename SUCCESS,
- typename FAILURE,
- typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM, typename SUCCESS, typename FAILURE>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, const Result<SUCCESS, FAILURE>& res) {
if (res == Success) {
if constexpr (traits::HasOperatorShiftLeft<STREAM&, SUCCESS>) {
diff --git a/src/tint/utils/rtti/traits.h b/src/tint/utils/rtti/traits.h
index 383a64d..00d3473 100644
--- a/src/tint/utils/rtti/traits.h
+++ b/src/tint/utils/rtti/traits.h
@@ -34,6 +34,11 @@
#include <type_traits>
#include <utility>
+// Predeclarations
+namespace tint {
+class StringStream;
+}
+
namespace tint::traits {
/// Convience type definition for std::decay<T>::type
@@ -222,35 +227,9 @@
////////////////////////////////////////////////////////////////////////////////
// IsOStream
////////////////////////////////////////////////////////////////////////////////
-namespace detail {
-/// Helper for determining whether the type T can be used as a stream writer
-template <typename T, typename ENABLE = void>
-struct IsOStream : std::false_type {};
-
-/// Specialization for types that declare a `static constexpr bool IsStreamWriter` member
template <typename T>
-struct IsOStream<T, std::void_t<decltype(T::IsStreamWriter)>> {
- /// Equal to T::IsStreamWriter
- static constexpr bool value = T::IsStreamWriter;
-};
-
-/// Specialization for std::ostream
-template <typename T>
-struct IsOStream<T, std::enable_if_t<std::is_same_v<T, std::ostream>>> : std::true_type {};
-
-/// Specialization for std::stringstream
-template <typename T>
-struct IsOStream<T, std::enable_if_t<std::is_same_v<T, std::stringstream>>> : std::true_type {};
-
-} // namespace detail
-
-/// Is true if the class T can be treated as an output stream
-template <typename T>
-static constexpr bool IsOStream = detail::IsOStream<T>::value;
-
-/// If `CONDITION` is true then EnableIfIsOStream resolves to type T, otherwise an invalid type.
-template <typename T = void>
-using EnableIfIsOStream = std::enable_if_t<IsOStream<T>, T>;
+concept IsOStream = std::is_same_v<T, std::ostream> || std::is_same_v<T, std::stringstream> ||
+ std::is_same_v<T, tint::StringStream>;
////////////////////////////////////////////////////////////////////////////////
// HasOperatorShiftLeft
diff --git a/src/tint/utils/templates/enums.tmpl.inc b/src/tint/utils/templates/enums.tmpl.inc
index 45f3945..f0079a3 100644
--- a/src/tint/utils/templates/enums.tmpl.inc
+++ b/src/tint/utils/templates/enums.tmpl.inc
@@ -84,7 +84,8 @@
/// @param out the stream to write to
/// @param value the {{$name}}
/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+template <typename STREAM>
+ requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, {{$name}} value) {
return out << ToString(value);
}
diff --git a/src/tint/utils/text/string_stream.h b/src/tint/utils/text/string_stream.h
index 9b3e20c..49b3d2f 100644
--- a/src/tint/utils/text/string_stream.h
+++ b/src/tint/utils/text/string_stream.h
@@ -56,9 +56,6 @@
std::is_same_v<SetFillRetTy, std::decay_t<T>>;
public:
- /// @see tint::traits::IsOStream
- static constexpr bool IsStreamWriter = true;
-
/// Constructor
StringStream();
/// Copy constructor