Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么这个C++;检测类型T是否有无效运算符(EDT const&;失败)的特征?_C++_Metaprogramming_Template Meta Programming - Fatal编程技术网

C++ 为什么这个C++;检测类型T是否有无效运算符(EDT const&;失败)的特征?

C++ 为什么这个C++;检测类型T是否有无效运算符(EDT const&;失败)的特征?,c++,metaprogramming,template-meta-programming,C++,Metaprogramming,Template Meta Programming,我试图使用SFINAE来检测作为模板参数T传递的类型是否有一个T::operator()(p const&),其中p也是一个模板参数。不幸的是,我无法让操作符()工作,尽管我可以让它为一个普通方法工作 下面是一些示例代码,演示了我面临的问题: #include <iostream> #include <iomanip> #include <utility> #include <type_traits> using namespace std;

我试图使用SFINAE来检测作为模板参数T传递的类型是否有一个T::operator()(p const&),其中p也是一个模板参数。不幸的是,我无法让操作符()工作,尽管我可以让它为一个普通方法工作

下面是一些示例代码,演示了我面临的问题:

#include <iostream>
#include <iomanip>
#include <utility>
#include <type_traits>

using namespace std;

struct has
{
    void operator()(int const&);    
};

struct hasNot1
{
    void operator()(int);   
};

struct hasNot2
{
    void operator()();  
};

struct hasNot3
{
    void operator()(float); 
};

struct hasNot4
{
};

template<typename T, typename EDT>
struct is_callable_oper
{
      private:
                    typedef char(&yes)[1];
                    typedef char(&no)[2];

                    template <typename U, void (U::*)(EDT const &)> struct
                                                                        Check;
                    template<typename>
                    static yes test(...);

                    template <typename U>
                    static no
                            test(Check<U, &U::operator()>*);

                public:
                    static constexpr bool value = sizeof(test<T>(0))
                                                                == sizeof(yes);
};

int main() {
    cout << boolalpha << is_callable_oper<has, int&>::value << " " 
         << is_callable_oper<has, int>::value << " "
         << is_callable_oper<hasNot1, int&>::value << " "
         << is_callable_oper<hasNot2, int&>::value << " "
         << is_callable_oper<hasNot3, int&>::value << " "
         << is_callable_oper<hasNot4, int&>::value << endl;
    return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
结构有
{
void运算符()(int const&);
};
结构hasNot1
{
void操作符()(int);
};
结构hasNot2
{
void运算符();
};
结构hasNot3
{
void操作符()(float);
};
结构hasNot4
{
};
模板
结构是可调用的
{
私人:
typedef字符(&yes)[1];
typedef字符(&no)[2];
模板结构
检查;
模板
静态是测试(…);
模板
静态否
测试(检查*);
公众:
静态constexpr bool值=sizeof(测试(0))
==sizeof(是);
};
int main(){

cout在更现代的编译器上,解决这类问题的典型方法是
void\t
习惯用法:。它是这样运行的。步骤1:

template <class T>
using void_t = void;  // avoid variadics for simplicity
对你的类型来说是合理的。这基本上就是你想要的特质检测。注意,有一些微妙之处涉及左值、右值、常量,但这将有点涉及到这里

现在,正如Sam在注释中所指出的,这个表达式是否合理包括隐式转换。因此,输出确实为true false。工作示例:


例如,您期望
is\u callable\u oper::value
为false。但是,显然可以使用
int
调用接受
常量int&
的函数。因此,您得到的是true。

您澄清了
运算符()
返回一个
void
,您希望严格匹配签名,忽略类型转换

如果是这样,那么您的预期结果应该是
false-true-false
,而不是
true-false-false

 is_callable_oper<has, int&>::value
由于
has
确实有一个
操作符()
接受
常量int&
参数,因此该测试应该通过

我的解决方案只是使用
std::is_same
来比较两种类型,如果
std::enable_
使模板解析候选失败,则使用
std::enable_

#include <type_traits>
#include <iostream>

struct has
{
    void operator()(int const&);
};

struct hasNot1
{
    void operator()(int);
};

struct hasNot2
{
    void operator()();
};

struct hasNot3
{
    void operator()(float);
};

struct hasNot4
{
};

template<typename T, typename P, typename foo=void>
class is_callable_oper : public std::false_type {};

template<typename T, typename P>
class is_callable_oper<T, P, typename std::enable_if<
         std::is_same<decltype(&T::operator()),
                      void (T::*)(const P &)>::value>::type>
    : public std::true_type {};

int main() {
    std::cout << std::boolalpha << is_callable_oper<has, int&>::value << " "
         << is_callable_oper<has, int>::value << " "
         << is_callable_oper<hasNot1, int&>::value << " "
         << is_callable_oper<hasNot2, int&>::value << " "
         << is_callable_oper<hasNot3, int&>::value << " "
          << is_callable_oper<hasNot4, int&>::value << std::endl;
    return 0;
}

你真的不可能得到一个更新的编译器吗?TMP在新版本的语言中非常简单。我可以用新的编译器用5行代码为你解决这个问题。我现在只能用这一行。我希望看到你的解决方案使用更现代的编译器;请与我分享。这里有一个非常微妙的问题。我如果一个函数的参数是,比如说一个
float
,你可以传递一个
int&
,因为它可以转换为一个
float
。你需要决定这是否是“可调用的”对于您来说,也可以不这样。在这种情况下,使用
decltype
declval
将导致您的操作员被视为可调用。如果您希望严格检查操作员签名,则只有在您还指定了操作员的返回类型时,才可以这样做。如果您使用
decltype
declval
,则正确的结果你的测试程序的lts应该是
true-false
@Sam Varshavchik,所以转换规则让我很头疼;很高兴知道。我到底应该如何使用decltype和declval来改进这一点?我的返回类型是fixed->void。我如何利用它?谢谢你的帮助!谢谢你的详细回答。我会花点时间仔细考虑一下在问任何问题之前,我一直想知道是否有任何方法来限制类型转换。@ BATBRAT山姆的答案可能比你想要的更好。虽然,我会说,这是一个有XY问题的情况。在C++中,你通常关心你是否能做些事情,例如是否有东西可以调用。某种类型。不是签名是否完全匹配。从某种意义上说,这样做可能会破坏隐式转换的契约。你完全正确-我不需要限制完全匹配;事实上,我不应该。比我的解决方案更好,考虑到OP要求的。而不是
常量int&
int&const&
…也就是说
int&
。这对可重载的调用运算符也不起作用。@SamVarshavchik,为什么int&const&会松开const?这就是不匹配的原因,不是吗?我也很好奇,如果不进行精确匹配,如何实现此测试-正如Nir Friedman正确指出的,我应该这样做ldn没有进行精确匹配。我对问题进行了编辑以反映这一点。你需要发布一个修改后的问题,该问题最少但明确地阐述了你试图实现的目标,最重要的是,显示了你已经完成的工作,并解释了你缺少的内容(这样你的问题就不会只是同义词)“请为我写代码”).现在,这个问题变得太复杂,很难理解。你应该从头开始。@SamVarshavchik观点很好。我将删除编辑并接受你的答案;然后,我将从头开始,正确地问一个问题。我绝对不希望任何人为我写代码:整个要点是理解我有足够的时间独自做这件事。
std::declval<T>()(declval<P>())
 is_callable_oper<has, int&>::value
 is_callable_oper<has, int>
#include <type_traits>
#include <iostream>

struct has
{
    void operator()(int const&);
};

struct hasNot1
{
    void operator()(int);
};

struct hasNot2
{
    void operator()();
};

struct hasNot3
{
    void operator()(float);
};

struct hasNot4
{
};

template<typename T, typename P, typename foo=void>
class is_callable_oper : public std::false_type {};

template<typename T, typename P>
class is_callable_oper<T, P, typename std::enable_if<
         std::is_same<decltype(&T::operator()),
                      void (T::*)(const P &)>::value>::type>
    : public std::true_type {};

int main() {
    std::cout << std::boolalpha << is_callable_oper<has, int&>::value << " "
         << is_callable_oper<has, int>::value << " "
         << is_callable_oper<hasNot1, int&>::value << " "
         << is_callable_oper<hasNot2, int&>::value << " "
         << is_callable_oper<hasNot3, int&>::value << " "
          << is_callable_oper<hasNot4, int&>::value << std::endl;
    return 0;
}
template<typename T, typename P>
class is_callable_oper<T, P,
        std::void_t<decltype( std::declval< void (T::*&)(const P &)>()=&T::operator())>>
    : public std::true_type {};