C++ 编写一个概念检查库,但在所有基本算术类型上都失败

C++ 编写一个概念检查库,但在所有基本算术类型上都失败,c++,concept,c++17,C++,Concept,C++17,当我测试基本算术类型(如int)和原始指针(如int*)是否可以预递增或后递增时,出现了问题 //has_operator_overload_functions.hpp namespace concept_check { template <class T> T create_T(); struct disambiguation_t2 {}; struct disambiguation_t1 { constexpr operator disambiguation_t2 ()

当我测试基本算术类型(如int)和原始指针(如int*)是否可以预递增或后递增时,出现了问题

//has_operator_overload_functions.hpp
namespace concept_check {
template <class T>
T create_T();

struct disambiguation_t2 {};
struct disambiguation_t1 {
    constexpr operator disambiguation_t2 () const noexcept;
};
}

# define create_has_op_overload_fn_test(fn_name, ret_t_of_op_to_test) \
template <class T>                                          \
auto has_ ## fn_name (disambiguation_t1) -> ret_t_of_op_to_test;     \
template <class T>                                          \
void has_ ## fn_name (disambiguation_t2);                    \
template <class T>                                          \
inline constexpr const bool has_ ## fn_name ## _v = !is_same_v<decltype(has_ ## fn_name <T>(disambiguation_t1{})), void>;

# define create_check_op_overload_fn_return_type_test(fn_name, ret_t_of_op_to_test, result_t) \
create_has_op_overload_fn_test(fn_name, ret_t_of_op_to_test) \                              
_create_check_op_overload_fn_return_type_test(fn_name, ret_t_of_op_to_test, result_t)

# define _create_check_op_overload_fn_return_type_test(fn_name, ret_t_of_op_to_test, result_t) \
template <class T>          \                                                         
constexpr const bool is_ ## fn_name () noexcept {      \                           

    if constexpr(has_ ## fn_name ## _v<T>)                  \                                 
        return is_convertible_v< ret_t_of_op_to_test , result_t >; \
    else             \                                
        return 0;                                \
}                                                  \
template <class T>                                      \
inline constexpr const bool is_ ## fn_name ## _v = is_ ## fn_name <T>();

namespace concept_check {
create_check_op_overload_fn_return_type_test(pre_incrementable, 
decltype(++create_T<T>()), T&)
create_check_op_overload_fn_return_type_test(post_incrementable, 
decltype(create_T<T>()++), T)
}//namespace concept_check
,命令行args-std=c++17-I。。然后运行我得到的二进制文件,它给出了以下输出:

incrementable

int
false
false

char
false
false

float
false
false

double
false
false

char*
false
false

void*
false
false

A
true
true

B
true
false

C
false
true

E
false
false

bool
false
false
正如您所看到的,所有基本算术类型和原始指针都没有通过可增量前/增量后测试

有人能解释为什么会发生这种情况,以及如何修复这种情况吗

create_check_op_overload_fn_return_type_test(pre_incrementable, decltype(++create_T<T>()), T&)
  • 第一个例子是欠约束的,因为它有效地测试
    ++mutable_arg
    给定一个虚构的
    arg mutable_arg变量,但主体对不可变变量进行操作(当然在大多数情况下不可递增)
  • 第二个示例是过度约束的,因为例如,如果调用
    int const immutable_variable=0
    作为一个参数,它有效地测试了
    ++immutable_arg
    ,但主体是在
    int
    变量上操作的

现在,可以对这些示例进行调整,使其约束在给定概念的
是可增量的。

请自问。如果链接坏了,我们什么都听不懂。如果代码太大,请将其缩减为最小的完整可验证示例。
create\u T
未声明。不要使用以两个下划线开头的标识符:它们是保留的,这意味着某些编译器或编译器提供的库可能定义它们或赋予它们特殊的内置含义。因此,您的意思是,如果++create__t()相当于++t{},但因为对于非类,默认初始化等于零初始化,因此它变成了++0,这使得is_pre_可递增返回0。@JiaHaoXu不,
create_T()
不涉及任何类型的初始化,也不等同于
T{}
(在我的回答中,我特别提到了具体的类
A
)。你不能执行
++0
,就像你不能执行
++3
++std::move(i)
(其中
i
是一个
int
变量)一样,因为语言的规则()这就是最重要的。我明白了。但是我仍然不明白为什么++int=++0,你能进一步解释一下吗?@Lucantion,当我定义create_has_op_重载_fn_test(可引用,decltype(*create_t())时,它对非类和类都很有效。@JiaHaoXu记得
create_t
与例如
int make_a_三(){return 3;}
,因此类比是
++make_a_三()
++3
一样毫无意义。例如,一元
*
和前缀increment之间的区别在于,只有后者(通常)修改其参数,这使得定义瞬时值变得很困难(这就是为什么语言决定不麻烦的原因)
incrementable

int
false
false

char
false
false

float
false
false

double
false
false

char*
false
false

void*
false
false

A
true
true

B
true
false

C
false
true

E
false
false

bool
false
false
create_check_op_overload_fn_return_type_test(pre_incrementable, decltype(++create_T<T>()), T&)
template<typename Arg>
auto under_constrained(Arg const& arg)
-> std::enable_if_t<is_pre_incrementable_v<Arg>>
{
    ++arg;
}

template<typename Arg>
auto over_constrained(Arg& arg)
-> std::enable_if_t<is_pre_incrementable_v<Arg>, std::decay_t<Arg>>
{
    auto copy = arg;
    ++copy;
    return copy;
}