在下面的代码中,当定义了SHOW_SFINAE_ON_TEMPLATED_ROUTINES_WORKS_AS_EXPECTED时,我们成功演示了SFINAE的方法实例。
但是,当定义了TRY_SFINAE_ON_CODE_BLOCK时,代码块上的替换失败,同时编译模板为" struct no_am" - 和编译错误。但是,编译器在编译时知道当模板是" struct no_am"时,不会执行这段代码。所以这次失败不应该是一个错误(或者我认为!)。
请解释为什么编译器可以在例程中应用SFINAE但无法在代码块上应用SFINAE。另外,如果有办法让编译器在代码块上应用SFINAE,请告诉我具体如何。
// Compiled via command:
// x86_64_6.2.0_posix_seh_rt_v5_rev1/mingw64/bin/x86_64-w64-mingw32-g++.exe -D_WIN64 -Wall -Wextra -Werror -std=c++11 -O3 -static-libgcc -static-libstdc++ sfinae_on_code_block.cc -o sfinae.exe
#define SHOW_SFINAE_ON_TEMPLATED_ROUTINES_WORKS_AS_EXPECTED
//#define TRY_SFINAE_ON_CODE_BLOCK
#include <fstream>
#include <iostream>
#include <thread>
#include <mutex>
template< typename T >
struct a_member_trait{
static const bool exists = false;
static const bool is_float = false;
};
template< class T >
class see_sfinae_member_traits
{
public:
see_sfinae_member_traits( T t ) : the_t(t)
{
}
T the_t;
#ifdef SHOW_SFINAE_ON_TEMPLATED_ROUTINES_WORKS_AS_EXPECTED
void speak( const std::string& msg )
{
std::cout << msg << ": ";
speak_sfinae<T>();
}
template< class X >
typename std::enable_if< a_member_trait<X>::exists == true &&
a_member_trait<X>::is_float == true >::type
speak_sfinae()
{
std::cout << "Has a_member, and that a_member is a float ["
<< the_t.a_member
<< "]"
<< std::endl;
}
template< class X >
typename std::enable_if< a_member_trait<X>::exists == true &&
a_member_trait<X>::is_float == false >::type
speak_sfinae()
{
std::cout << "Has a_member, and that a_member is NOT a float ["
<< the_t.a_member
<< "]"
<< std::endl;
}
template< class X >
typename std::enable_if< a_member_trait<X>::exists == false &&
a_member_trait<X>::is_float == false >::type
speak_sfinae()
{
std::cout << "Does NOT have a_member, float or otherwise"
<< std::endl;
}
#endif
#ifdef TRY_SFINAE_ON_CODE_BLOCK
void tell( const std::string& msg )
{
std::cout << msg << ": ";
tell_all<T>();
}
template< class X >
void tell_all()
{
std::cout << "from tell all: ";
if( a_member_trait<X>::exists == true && a_member_trait<X>::is_float == true )
{
std::cout << "Has a_member, and that a_member is a float ["
<< the_t.a_member
<< "]"
<< std::endl;
}
if( a_member_trait<X>::exists == true && a_member_trait<X>::is_float == false )
{
std::cout << "Has a_member, and that a_member is NOT a float"
<< the_t.a_member
<< "]"
<< std::endl;
}
if( a_member_trait<X>::exists == false && a_member_trait<X>::is_float == false )
{
std::cout << "Does NOT have a_member, float or otherwise"
<< std::endl;
}
}
#endif
};
struct has_fam
{
float a_member{ 1.1f };
};
struct has_iam
{
int a_member{ 1 };
};
struct no_am
{
int b_member{ 2 };
};
template<>
struct a_member_trait< has_fam >{
static const bool exists = true;
static const bool is_float = true;
};
template<>
struct a_member_trait< has_iam >{
static const bool exists = true;
static const bool is_float = false;
};
int main()
{
has_fam x_fam;
has_iam x_iam;
no_am x_noam;
see_sfinae_member_traits< has_fam > ht_fam( x_fam );
see_sfinae_member_traits< has_iam > ht_iam( x_iam );
see_sfinae_member_traits< no_am > ht_noam( x_noam );
#ifdef SHOW_SFINAE_ON_TEMPLATED_ROUTINES_WORKS_AS_EXPECTED
ht_fam.speak( "hast_fam" );
ht_iam.speak( "hast_iam" );
ht_noam.speak( "not_am" );
#endif
#ifdef TRY_SFINAE_ON_CODE_BLOCK
ht_fam.tell( "hast_fam" );
ht_iam.tell( "hast_iam" );
ht_noam.tell( "not_am" );
#endif
return 0;
}