尝试专门化成员方法。
阅读上一个问题:std::enable_if to conditionally compile a member function
我完全明白我做错了什么。
#include <string>
#include <iostream>
#include <type_traits>
template<typename T>
class Traits
{
};
struct Printer
{
template<typename T>
typename std::enable_if<!std::is_function<decltype(Traits<T>::converter)>::value, void>::type
operator()(T const& object)
{
std::cout << object;
}
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
operator()(T const& object)
{
std::cout << Traits<T>::converter(object);
}
};
template<>
class Traits<std::string>
{
public:
static std::size_t converter(std::string const& object)
{
return object.size();
}
};
int main()
{
using namespace std::string_literals;
Printer p;
p(5);
p("This is a C-string");
p("This is a C++String"s); // This compiles.
}
编译提供:
> g++ -std=c++1z X.cpp
X.cpp:42:5: error: no matching function for call to object of type 'Printer'
p(5);
^
X.cpp:14:5: note: candidate template ignored: substitution failure [with T = int]: no member named 'converter' in 'Traits<int>'
operator()(T const& object)
^
X.cpp:20:5: note: candidate template ignored: substitution failure [with T = int]: no member named 'converter' in 'Traits<int>'
operator()(T const& object)
^
他们似乎都失败了,因为他们看不到方法converter
。但我试图使用SFINE和std::enable_if
来识别这个函数不存在,因此只实例化其中一个方法。
为每种类型生成相同的错误:
X.cpp:43:5: error: no matching function for call to object of type 'Printer'
p("This is a C-string");
^
X.cpp:14:5: note: candidate template ignored: substitution failure [with T = char [19]]: no member named 'converter' in 'Traits<char [19]>'
operator()(T const& object)
^
X.cpp:20:5: note: candidate template ignored: substitution failure [with T = char [19]]: no member named 'converter' in 'Traits<char [19]>'
operator()(T const& object)
^
注意:它会编译std::string
版本。
答案 0 :(得分:1)
您可以遵循私有帮助函数,并使用重载决策来优先选择SFINAE-d过载 - 并且没有负面的SFINAE-d:
struct Printer
{
template <class T>
void operator()(T const& object) {
call_impl(object, 0);
}
private:
// selected if Traits<T>::converter exists and is a function
// preferred in this case because int is better than ...
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
call_impl(T const& object, int)
{
std::cout << Traits<T>::converter(object);
}
// selected if either Traits<T>::converter doesn't exist or isn't a function
template<typename T>
void call_impl(T const& object, ...)
{
std::cout << object;
}
};
我们将在C ++ 2a中使用约束函数获得的一个好处是,我们可以在没有额外帮助的情况下完成此任务:
struct Printer
{
template <class T>
requires std::is_function<decltype(Traits<T>::converter)>::value
void operator()(T const& object)
{
std::cout << Traits<T>::converter(object);
}
template <class T>
void operator()(T const& object)
{
std::cout << object;
}
};
答案 1 :(得分:0)
如何将非功能converter
添加到非专业特征中?
template<typename T>
class Traits
{
public: enum class Dummy{nothing};
public: static Dummy const converter = Dummy::nothing;
};
答案 2 :(得分:0)
问题在于SFINAE的工作原理。当替换失败时,整个功能将从程序中取出。因此,即使您的谓词typename std::enable_if<!std::is_function<decltype(Traits<T>::converter)>::value, void>::type
意图捕获false
案例,converter
的不存在也会导致重载被取消。
最简单的解决方法是这样的:
struct Printer
{
template<typename T>
void
impl(T const& object, ...)
{
std::cout << object;
}
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
impl(T const& object, void*)
{
std::cout << Traits<T>::converter(object);
}
template<typename T>
void
operator()(T const& x)
{
return impl(x, nullptr);
}
};
基本上:您为编译器提供了一些在不使用谓词的情况下始终可以工作的东西。这里的诀窍是nullptr
将与void*
而不是...
匹配,因此它会做你想要的。
如果您希望获得真正的乐趣,可以创建一个返回类型为has_converter
或true_type
的{{1}}函数,并重置该实现。
false_type
可以想象帮助函数或模板struct Printer
{
template<typename T>
std::false_type
has_converter(T const& object, ...);
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, std::true_type>::type
has_converter(T const& object, void*);
template<typename T>
void impl(T const& x, std::false_type)
{
std::cout << x;
}
template<typename T>
void impl(T const& x, std::true_type)
{
std::cout << Traits<T>::converter(x);
}
template<typename T>
void
operator()(T const& x)
{
return impl(x, decltype(has_converter(x, nullptr))());
}
};
使得使用此属性更加容易(使用与上面相同的技术)。
constexpr bool