英文:
Constraining parameter type in derived class to fit capabilities of base class
问题
我有一个名为`variant2`的类型,它派生自`std::variant`。现在我想要能够提前捕获潜在的赋值错误,以防分配的类型与其中一个变体类型不匹配。
然而,我想出的方法存在一个问题,即内部`std::variant`的`typedef`直到右括号才完整,所以我无法通过一个概念来传递它。我有哪些备选方案?
(注意:在实际生产代码中,函数`assign`要复杂得多,因此我想为了用户友好性而能够提前捕获错误。)
[演示][1]
#include
#include
#include
#include <type_traits>
#include
template <typename T, typename Variant>
struct is_variant_type;
template <typename T, template <typename...> typename Var, typename... Args>
struct is_variant_type<T, Var<Args...>>
: public std::disjunction<std::is_same<T, Args>...> {};
template <typename T, typename Variant>
concept variant_type = is_variant_type<T, Variant>::value;
template
struct variant2 : public std::variant<std::monostate, int, T>
{
using inner_variant_type = variant2::variant;
template <variant_type<inner_variant_type> U>
auto assign(const U& arg)
{
*this = arg;
}
};
int main()
{
variant2std::string var;
var.assign(2);
}
产生的错误:
<source>:19:42: 错误:对不完整类型“struct variant2<T>”的无效使用
19 | using inner_variant_type = variant2::variant;
| ^~~~~~~
<source>:18:8: 注意:直到右括号才完成对“struct variant2<T>”的定义
18 | struct variant2 : public std::variant<std::monostate, int, T> {
| ^~~~~~~~
<source>:21:28: 错误:在此作用域中未声明“inner_variant_type”;你是不是要说“is_variant_type”?
21 | template <variant_type<inner_variant_type> U>
| ^~~~~~~~~~~~~~~~~~
| is_variant_type
等等。
[1]: https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1DIApACYAQuYukl9ZATwDKjdAGFUtAK4sGe1wAyeAyYAHI%2BAEaYxBIAbKQADqgKhE4MHt6%2BekkpjgJBIeEsUTFc8XaYDmlCBEzEBBk%2Bfly2mPZ5DDV1BAVhkdFxtrX1jVktCsM9wX3FA2UAlLaoXsTI7BzmAMzByN5YANQmm25oDGsJBApH2CYaAIJbO3uYh8dOE8SYrNe3D2bbZ2erzcH2CwB%2B90egK8ByObgIAE8EpgAPoEYhMQhXTY3SH/J4wl5wgBudTwhgIEIe9wImBYCQMtOBiORzDY%2BwAKqR9izG...
英文:
I have a type variant2
derived from std::variant
. Now I want to be able to early capture potential assignment errors in case the assigned type doesn't match one of the variants types.
However, the way I came up with suffers from the issue that the typedef
of the inner std::variant
is incomplete until the closing braces, so I can't pass that through a concept. What alternatives do I have?
(Note: In production code the function assign is a lot more complicated, hence I want to be able to capture errors for the sake of user-friendliness early.)
#include <concepts>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
template <typename T, typename Variant>
struct is_variant_type;
template <typename T, template <typename...> typename Var, typename... Args>
struct is_variant_type<T, Var<Args...>>
: public std::disjunction<std::is_same<T, Args>...> {};
template <typename T, typename Variant>
concept variant_type = is_variant_type<T, Variant>::value;
template <typename T>
struct variant2 : public std::variant<std::monostate, int, T>
{
using inner_variant_type = variant2::variant;
template <variant_type<inner_variant_type> U>
auto assign(const U& arg)
{
*this = arg;
}
};
int main()
{
variant2<std::string> var;
var.assign(2);
}
Yields:
<source>:19:42: error: invalid use of incomplete type 'struct variant2<T>'
19 | using inner_variant_type = variant2::variant;
| ^~~~~~~
<source>:18:8: note: definition of 'struct variant2<T>' is not complete until the closing brace
18 | struct variant2 : public std::variant<std::monostate, int, T> {
| ^~~~~~~~
<source>:21:28: error: 'inner_variant_type' was not declared in this scope; did you mean 'is_variant_type'?
21 | template <variant_type<inner_variant_type> U>
| ^~~~~~~~~~~~~~~~~~
| is_variant_type
etc.
答案1
得分: 4
You are missing a typename
keyword, for the dependent type variant2::variant
, in the alias declaration inside the class variant2
.
Additionally, you have to mention which operator=
, that you meant at the line *this = var;
, which is by default not visible to the child. You can have more read here: https://stackoverflow.com/questions/1567730/inheritance-and-templates-in-c-why-are-inherited-members-invisible
template <typename T>
struct variant2 : public std::variant<std::monostate, int, T>
{
using inner_variant_type = typename variant2::variant; // required
// required to mention that the operator= is from the parent !!
using std::variant<std::monostate, int, T>::operator=;
template <variant_type<inner_variant_type> U>
auto assign(const U& var) {
*this = var;
}
};
英文:
You are missing a typename
keyword, for the dependent type variant2::variant
, in the alias declaration inside the class variant2
.
Additionally, you have to mention which operator=
, that you meant at the line *this = var;
, which is by default not visible to the child. You can have more read here: https://stackoverflow.com/questions/1567730/inheritance-and-templates-in-c-why-are-inherited-members-invisible
template <typename T>
struct variant2 : public std::variant<std::monostate, int, T>
{
using inner_variant_type = typename variant2::variant;
// ^^^^^^^^ ---> required
// required to mention, that the operator= is from the parent !!
using std::variant<std::monostate, int, T>::operator=;
template <variant_type<inner_variant_type> U>
auto assign(const U& var) {
*this = var;
}
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论